1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.dhcp;
18 
19 import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
20 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ALL;
21 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY;
22 
23 import android.net.DhcpResults;
24 import android.net.LinkAddress;
25 import android.net.metrics.DhcpErrorEvent;
26 import android.net.networkstack.aidl.dhcp.DhcpOption;
27 import android.os.Build;
28 import android.os.SystemProperties;
29 import android.system.OsConstants;
30 import android.text.TextUtils;
31 
32 import androidx.annotation.NonNull;
33 import androidx.annotation.Nullable;
34 import androidx.annotation.VisibleForTesting;
35 
36 import com.android.net.module.util.DomainUtils;
37 import com.android.net.module.util.Inet4AddressUtils;
38 
39 import java.io.UnsupportedEncodingException;
40 import java.net.Inet4Address;
41 import java.net.UnknownHostException;
42 import java.nio.BufferUnderflowException;
43 import java.nio.ByteBuffer;
44 import java.nio.ByteOrder;
45 import java.nio.ShortBuffer;
46 import java.nio.charset.StandardCharsets;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.List;
50 
51 /**
52  * Defines basic data and operations needed to build and use packets for the
53  * DHCP protocol.  Subclasses create the specific packets used at each
54  * stage of the negotiation.
55  *
56  * @hide
57  */
58 public abstract class DhcpPacket {
59     protected static final String TAG = "DhcpPacket";
60 
61     // TODO: use NetworkStackConstants.IPV4_MIN_MTU once this class is moved to the network stack.
62     private static final int IPV4_MIN_MTU = 68;
63 
64     // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
65     // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the
66     // DHCP client timeout.
67     public static final String CONFIG_MINIMUM_LEASE = "dhcp_minimum_lease";
68     public static final int DEFAULT_MINIMUM_LEASE = 60;
69     public static final int INFINITE_LEASE = (int) 0xffffffff;
70 
71     public static final Inet4Address INADDR_ANY = IPV4_ADDR_ANY;
72     public static final Inet4Address INADDR_BROADCAST = IPV4_ADDR_ALL;
73     public static final byte[] ETHER_BROADCAST = new byte[] {
74             (byte) 0xff, (byte) 0xff, (byte) 0xff,
75             (byte) 0xff, (byte) 0xff, (byte) 0xff,
76     };
77 
78     /**
79      * Packet encapsulations.
80      */
81     public static final int ENCAP_L2 = 0;    // EthernetII header included
82     public static final int ENCAP_L3 = 1;    // IP/UDP header included
83     public static final int ENCAP_BOOTP = 2; // BOOTP contents only
84 
85     /**
86      * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
87      */
88     public static final int MIN_PACKET_LENGTH_BOOTP = 236;  // See diagram in RFC 2131, section 2.
89     public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
90     public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
91 
92     public static final int HWADDR_LEN = 16;
93     public static final int MAX_OPTION_LEN = 255;
94 
95     // The lower boundary for V6ONLY_WAIT.
96     public static final long MIN_V6ONLY_WAIT_MS = 300_000;
97     public static final long V6ONLY_PREFERRED_ABSENCE = -1L;
98 
99     /**
100      * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
101      * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
102      * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
103      * because in general it is risky to assume that the hardware is able to send/receive packets
104      * larger than 1500 bytes even if the network supports it.
105      */
106     private static final int MIN_MTU = 1280;
107     private static final int MAX_MTU = 1500;
108 
109     /**
110      * IP layer definitions.
111      */
112     private static final byte IP_TYPE_UDP = (byte) 0x11;
113 
114     /**
115      * IP: Version 4, Header Length 20 bytes
116      */
117     private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
118 
119     /**
120      * IP: Flags 0, Fragment Offset 0, Don't Fragment
121      */
122     private static final short IP_FLAGS_OFFSET = (short) 0x4000;
123 
124     /**
125      * IP: TOS
126      */
127     private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
128 
129     /**
130      * IP: TTL -- use default 64 from RFC1340
131      */
132     private static final byte IP_TTL = (byte) 0x40;
133 
134     /**
135      * The client DHCP port.
136      */
137     public static final short DHCP_CLIENT = (short) 68;
138 
139     /**
140      * The server DHCP port.
141      */
142     public static final short DHCP_SERVER = (short) 67;
143 
144     /**
145      * The message op code indicating a request from a client.
146      */
147     public static final byte DHCP_BOOTREQUEST = (byte) 1;
148 
149     /**
150      * The message op code indicating a response from the server.
151      */
152     public static final byte DHCP_BOOTREPLY = (byte) 2;
153 
154     /**
155      * The code type used to identify an Ethernet MAC address in the
156      * Client-ID field.
157      */
158     protected static final byte CLIENT_ID_ETHER = (byte) 1;
159 
160     /**
161      * The maximum length of a packet that can be constructed.
162      */
163     protected static final int MAX_LENGTH = 1500;
164 
165     /**
166      * The magic cookie that identifies this as a DHCP packet instead of BOOTP.
167      */
168     public static final int DHCP_MAGIC_COOKIE = 0x63825363;
169 
170     /**
171      * DHCP Optional Type: DHCP Subnet Mask
172      */
173     public static final byte DHCP_SUBNET_MASK = 1;
174     protected Inet4Address mSubnetMask;
175 
176     /**
177      * DHCP Optional Type: DHCP Router
178      */
179     public static final byte DHCP_ROUTER = 3;
180     protected List <Inet4Address> mGateways;
181 
182     /**
183      * DHCP Optional Type: DHCP DNS Server
184      */
185     public static final byte DHCP_DNS_SERVER = 6;
186     protected List<Inet4Address> mDnsServers;
187 
188     /**
189      * DHCP Optional Type: DHCP Host Name
190      */
191     public static final byte DHCP_HOST_NAME = 12;
192     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
193     public String mHostName;
194 
195     /**
196      * DHCP Optional Type: DHCP DOMAIN NAME
197      */
198     public static final byte DHCP_DOMAIN_NAME = 15;
199     protected String mDomainName;
200 
201     /**
202      * DHCP Optional Type: DHCP Interface MTU
203      */
204     public static final byte DHCP_MTU = 26;
205     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
206     public Short mMtu;
207 
208     /**
209      * DHCP Optional Type: DHCP BROADCAST ADDRESS
210      */
211     public static final byte DHCP_BROADCAST_ADDRESS = 28;
212     protected Inet4Address mBroadcastAddress;
213 
214     /**
215      * DHCP Optional Type: Vendor specific information
216      */
217     public static final byte DHCP_VENDOR_INFO = 43;
218     protected String mVendorInfo;
219 
220     /**
221      * Value of the vendor specific option used to indicate that the network is metered
222      */
223     public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED";
224 
225     /**
226      * DHCP Optional Type: Option overload option
227      */
228     public static final byte DHCP_OPTION_OVERLOAD = 52;
229 
230     /**
231      * Possible values of the option overload option.
232      */
233     private static final byte OPTION_OVERLOAD_FILE = 1;
234     private static final byte OPTION_OVERLOAD_SNAME = 2;
235     private static final byte OPTION_OVERLOAD_BOTH = 3;
236 
237     /**
238      * DHCP Optional Type: DHCP Requested IP Address
239      */
240     public static final byte DHCP_REQUESTED_IP = 50;
241     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
242     public Inet4Address mRequestedIp;
243 
244     /**
245      * DHCP Optional Type: DHCP Lease Time
246      */
247     public static final byte DHCP_LEASE_TIME = 51;
248     protected Integer mLeaseTime;
249 
250     /**
251      * DHCP Optional Type: DHCP Message Type
252      */
253     public static final byte DHCP_MESSAGE_TYPE = 53;
254     // the actual type values
255     public static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
256     public static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
257     public static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
258     public static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
259     public static final byte DHCP_MESSAGE_TYPE_ACK = 5;
260     public static final byte DHCP_MESSAGE_TYPE_NAK = 6;
261     public static final byte DHCP_MESSAGE_TYPE_RELEASE = 7;
262     public static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
263 
264     /**
265      * DHCP Optional Type: DHCP Server Identifier
266      */
267     public static final byte DHCP_SERVER_IDENTIFIER = 54;
268     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
269     public Inet4Address mServerIdentifier;
270 
271     /**
272      * DHCP Optional Type: DHCP Parameter List
273      */
274     public static final byte DHCP_PARAMETER_LIST = 55;
275     protected byte[] mRequestedParams;
276 
277     /**
278      * DHCP Optional Type: DHCP MESSAGE
279      */
280     public static final byte DHCP_MESSAGE = 56;
281     protected String mMessage;
282 
283     /**
284      * DHCP Optional Type: Maximum DHCP Message Size
285      */
286     public static final byte DHCP_MAX_MESSAGE_SIZE = 57;
287     protected Short mMaxMessageSize;
288 
289     /**
290      * DHCP Optional Type: DHCP Renewal Time Value
291      */
292     public static final byte DHCP_RENEWAL_TIME = 58;
293     protected Integer mT1;
294 
295     /**
296      * DHCP Optional Type: Rebinding Time Value
297      */
298     public static final byte DHCP_REBINDING_TIME = 59;
299     protected Integer mT2;
300 
301     /**
302      * DHCP Optional Type: Vendor Class Identifier
303      */
304     public static final byte DHCP_VENDOR_CLASS_ID = 60;
305     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
306     public String mVendorId;
307 
308     /**
309      * DHCP Optional Type: DHCP Client Identifier
310      */
311     public static final byte DHCP_CLIENT_IDENTIFIER = 61;
312     protected byte[] mClientId;
313 
314     /**
315      * DHCP Optional Type: DHCP User Class option
316      */
317     public static final byte DHCP_USER_CLASS = 77;
318     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
319     public byte[] mUserClass;
320 
321     /**
322      * DHCP zero-length Optional Type: Rapid Commit. Per RFC4039, both DHCPDISCOVER and DHCPACK
323      * packet may include this option.
324      */
325     public static final byte DHCP_RAPID_COMMIT = 80;
326     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
327     public boolean mRapidCommit;
328 
329     /**
330      * DHCP IPv6-Only Preferred Option(RFC 8925).
331      * Indicate that a host supports an IPv6-only mode and willing to forgo obtaining an IPv4
332      * address for V6ONLY_WAIT period if the network provides IPv6 connectivity. V6ONLY_WAIT
333      * is 32-bit unsigned integer, so the Integer value cannot be used as-is.
334      */
335     public static final byte DHCP_IPV6_ONLY_PREFERRED = (byte) 108;
336     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
337     public Integer mIpv6OnlyWaitTime;
338 
339     public static final byte DHCP_CAPTIVE_PORTAL = (byte) 114;
340     protected String mCaptivePortalUrl;
341 
342     /**
343      * DHCP Optional Type: Domain Search List, domain suffixes are space separated.
344      */
345     public static final byte DHCP_DOMAIN_SEARCHLIST = (byte) 119;
346     protected List<String> mDmnSrchList;
347 
348     /**
349      * DHCP zero-length option code: pad
350      */
351     public static final byte DHCP_OPTION_PAD = 0x00;
352 
353     /**
354      * DHCP zero-length option code: end of options
355      */
356     public static final byte DHCP_OPTION_END = (byte) 0xff;
357 
358     /**
359      * The transaction identifier used in this particular DHCP negotiation
360      */
361     protected final int mTransId;
362 
363     /**
364      * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only.
365      */
366     protected final short mSecs;
367 
368     /**
369      * The IP address of the client host.  This address is typically
370      * proposed by the client (from an earlier DHCP negotiation) or
371      * supplied by the server.
372      */
373     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
374     public final Inet4Address mClientIp;
375     protected final Inet4Address mYourIp;
376     private final Inet4Address mNextIp;
377     protected final Inet4Address mRelayIp;
378 
379     /**
380      * Does the client request a broadcast response?
381      */
382     protected boolean mBroadcast;
383 
384     /**
385      * The six-octet MAC of the client.
386      */
387     protected final byte[] mClientMac;
388 
389     /**
390      * The server host name from server.
391      */
392     protected String mServerHostName;
393 
394     /**
395      * The customized DHCP client options to be sent.
396      */
397     @Nullable
398     protected List<DhcpOption> mCustomizedClientOptions;
399 
400     /**
401      * Asks the packet object to create a ByteBuffer serialization of
402      * the packet for transmission.
403      */
buildPacket(int encap, short destUdp, short srcUdp)404     public abstract ByteBuffer buildPacket(int encap, short destUdp,
405         short srcUdp);
406 
407     /**
408      * Allows the concrete class to fill in packet-type-specific details,
409      * typically optional parameters at the end of the packet.
410      */
finishPacket(ByteBuffer buffer)411     abstract void finishPacket(ByteBuffer buffer);
412 
413     // Set in unit tests, to ensure that the test does not break when run on different devices and
414     // on different releases.
415     static String sTestOverrideVendorId = null;
416 
DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac, boolean broadcast)417     protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
418                          Inet4Address nextIp, Inet4Address relayIp,
419                          byte[] clientMac, boolean broadcast) {
420         mTransId = transId;
421         mSecs = secs;
422         mClientIp = clientIp;
423         mYourIp = yourIp;
424         mNextIp = nextIp;
425         mRelayIp = relayIp;
426         mClientMac = clientMac;
427         mBroadcast = broadcast;
428     }
429 
430     /**
431      * Returns the transaction ID.
432      */
getTransactionId()433     public int getTransactionId() {
434         return mTransId;
435     }
436 
437     /**
438      * Returns the client MAC.
439      */
getClientMac()440     public byte[] getClientMac() {
441         return mClientMac;
442     }
443 
444     // TODO: refactor DhcpClient to set clientId when constructing packets and remove
445     // hasExplicitClientId logic
446     /**
447      * Returns whether a client ID was set in the options for this packet.
448      */
hasExplicitClientId()449     public boolean hasExplicitClientId() {
450         return mClientId != null;
451     }
452 
453     /**
454      * Convenience method to return the client ID if it was set explicitly, or null otherwise.
455      */
456     @Nullable
getExplicitClientIdOrNull()457     public byte[] getExplicitClientIdOrNull() {
458         return hasExplicitClientId() ? getClientId() : null;
459     }
460 
461     /**
462      * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID
463      * based on the hardware address.
464      */
getClientId()465     public byte[] getClientId() {
466         final byte[] clientId;
467         if (hasExplicitClientId()) {
468             clientId = Arrays.copyOf(mClientId, mClientId.length);
469         } else {
470             clientId = new byte[mClientMac.length + 1];
471             clientId[0] = CLIENT_ID_ETHER;
472             System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length);
473         }
474         return clientId;
475     }
476 
477     /**
478      * Returns whether a parameter is included in the parameter request list option of this packet.
479      *
480      * <p>If there is no parameter request list option in the packet, false is returned.
481      *
482      * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}.
483      */
hasRequestedParam(byte paramId)484     public boolean hasRequestedParam(byte paramId) {
485         if (mRequestedParams == null) {
486             return false;
487         }
488 
489         for (byte reqParam : mRequestedParams) {
490             if (reqParam == paramId) {
491                 return true;
492             }
493         }
494         return false;
495     }
496 
497     /**
498      * Creates a new L3 packet (including IP header) containing the
499      * DHCP udp packet.  This method relies upon the delegated method
500      * finishPacket() to insert the per-packet contents.
501      */
fillInPacket(int encap, Inet4Address destIp, Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf, byte requestCode, boolean broadcast)502     protected void fillInPacket(int encap, Inet4Address destIp,
503         Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf,
504         byte requestCode, boolean broadcast) {
505         byte[] destIpArray = destIp.getAddress();
506         byte[] srcIpArray = srcIp.getAddress();
507         int ipHeaderOffset = 0;
508         int ipLengthOffset = 0;
509         int ipChecksumOffset = 0;
510         int endIpHeader = 0;
511         int udpHeaderOffset = 0;
512         int udpLengthOffset = 0;
513         int udpChecksumOffset = 0;
514 
515         buf.clear();
516         buf.order(ByteOrder.BIG_ENDIAN);
517 
518         if (encap == ENCAP_L2) {
519             buf.put(ETHER_BROADCAST);
520             buf.put(mClientMac);
521             buf.putShort((short) OsConstants.ETH_P_IP);
522         }
523 
524         // if a full IP packet needs to be generated, put the IP & UDP
525         // headers in place, and pre-populate with artificial values
526         // needed to seed the IP checksum.
527         if (encap <= ENCAP_L3) {
528             ipHeaderOffset = buf.position();
529             buf.put(IP_VERSION_HEADER_LEN);
530             buf.put(IP_TOS_LOWDELAY);    // tos: IPTOS_LOWDELAY
531             ipLengthOffset = buf.position();
532             buf.putShort((short)0);  // length
533             buf.putShort((short)0);  // id
534             buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment
535             buf.put(IP_TTL);    // TTL: use default 64 from RFC1340
536             buf.put(IP_TYPE_UDP);
537             ipChecksumOffset = buf.position();
538             buf.putShort((short) 0); // checksum
539 
540             buf.put(srcIpArray);
541             buf.put(destIpArray);
542             endIpHeader = buf.position();
543 
544             // UDP header
545             udpHeaderOffset = buf.position();
546             buf.putShort(srcUdp);
547             buf.putShort(destUdp);
548             udpLengthOffset = buf.position();
549             buf.putShort((short) 0); // length
550             udpChecksumOffset = buf.position();
551             buf.putShort((short) 0); // UDP checksum -- initially zero
552         }
553 
554         // DHCP payload
555         buf.put(requestCode);
556         buf.put((byte) 1); // Hardware Type: Ethernet
557         buf.put((byte) mClientMac.length); // Hardware Address Length
558         buf.put((byte) 0); // Hop Count
559         buf.putInt(mTransId);  // Transaction ID
560         buf.putShort(mSecs); // Elapsed Seconds
561 
562         if (broadcast) {
563             buf.putShort((short) 0x8000); // Flags
564         } else {
565             buf.putShort((short) 0x0000); // Flags
566         }
567 
568         buf.put(mClientIp.getAddress());
569         buf.put(mYourIp.getAddress());
570         buf.put(mNextIp.getAddress());
571         buf.put(mRelayIp.getAddress());
572         buf.put(mClientMac);
573         buf.position(buf.position() +
574                      (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
575                      + 64     // empty server host name (64 bytes)
576                      + 128);  // empty boot file name (128 bytes)
577         buf.putInt(DHCP_MAGIC_COOKIE); // magic number
578         finishPacket(buf);
579 
580         // round up to an even number of octets
581         if ((buf.position() & 1) == 1) {
582             buf.put((byte) 0);
583         }
584 
585         // If an IP packet is being built, the IP & UDP checksums must be
586         // computed.
587         if (encap <= ENCAP_L3) {
588             // fix UDP header: insert length
589             short udpLen = (short)(buf.position() - udpHeaderOffset);
590             buf.putShort(udpLengthOffset, udpLen);
591             // fix UDP header: checksum
592             // checksum for UDP at udpChecksumOffset
593             int udpSeed = 0;
594 
595             // apply IPv4 pseudo-header.  Read IP address src and destination
596             // values from the IP header and accumulate checksum.
597             udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2));
598             udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4));
599             udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6));
600             udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8));
601 
602             // accumulate extra data for the pseudo-header
603             udpSeed += IP_TYPE_UDP;
604             udpSeed += udpLen;
605             // and compute UDP checksum
606             buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed,
607                                                              udpHeaderOffset,
608                                                              buf.position()));
609             // fix IP header: insert length
610             buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset));
611             // fixup IP-header checksum
612             buf.putShort(ipChecksumOffset,
613                          (short) checksum(buf, 0, ipHeaderOffset, endIpHeader));
614         }
615     }
616 
617     /**
618      * Converts a signed short value to an unsigned int value.  Needed
619      * because Java does not have unsigned types.
620      */
intAbs(short v)621     private static int intAbs(short v) {
622         return v & 0xFFFF;
623     }
624 
625     /**
626      * Performs an IP checksum (used in IP header and across UDP
627      * payload) on the specified portion of a ByteBuffer.  The seed
628      * allows the checksum to commence with a specified value.
629      */
checksum(ByteBuffer buf, int seed, int start, int end)630     private int checksum(ByteBuffer buf, int seed, int start, int end) {
631         int sum = seed;
632         int bufPosition = buf.position();
633 
634         // set position of original ByteBuffer, so that the ShortBuffer
635         // will be correctly initialized
636         buf.position(start);
637         ShortBuffer shortBuf = buf.asShortBuffer();
638 
639         // re-set ByteBuffer position
640         buf.position(bufPosition);
641 
642         short[] shortArray = new short[(end - start) / 2];
643         shortBuf.get(shortArray);
644 
645         for (short s : shortArray) {
646             sum += intAbs(s);
647         }
648 
649         start += shortArray.length * 2;
650 
651         // see if a singleton byte remains
652         if (end != start) {
653             short b = buf.get(start);
654 
655             // make it unsigned
656             if (b < 0) {
657                 b += 256;
658             }
659 
660             sum += b * 256;
661         }
662 
663         sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF);
664         sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF);
665         int negated = ~sum;
666         return intAbs((short) negated);
667     }
668 
669     /**
670      * Adds an optional parameter containing a single byte value.
671      */
addTlv(ByteBuffer buf, byte type, byte value)672     protected static void addTlv(ByteBuffer buf, byte type, byte value) {
673         buf.put(type);
674         buf.put((byte) 1);
675         buf.put(value);
676     }
677 
678     /**
679      * Adds an optional parameter containing zero-length value.
680      */
addTlv(ByteBuffer buf, byte type)681     protected static void addTlv(ByteBuffer buf, byte type) {
682         buf.put(type);
683         buf.put((byte) 0);
684     }
685 
686     /**
687      * Adds an optional parameter containing an array of bytes.
688      *
689      * <p>This method is a no-op if the payload argument is null.
690      */
addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload)691     protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) {
692         if (payload != null) {
693             if (payload.length > MAX_OPTION_LEN) {
694                 throw new IllegalArgumentException("DHCP option too long: "
695                         + payload.length + " vs. " + MAX_OPTION_LEN);
696             }
697             buf.put(type);
698             buf.put((byte) payload.length);
699             buf.put(payload);
700         }
701     }
702 
703     /**
704      * Adds an optional parameter containing an IP address.
705      *
706      * <p>This method is a no-op if the address argument is null.
707      */
addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr)708     protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) {
709         if (addr != null) {
710             addTlv(buf, type, addr.getAddress());
711         }
712     }
713 
714     /**
715      * Adds an optional parameter containing a list of IP addresses.
716      *
717      * <p>This method is a no-op if the addresses argument is null or empty.
718      */
addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs)719     protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) {
720         if (addrs == null || addrs.size() == 0) return;
721 
722         int optionLen = 4 * addrs.size();
723         if (optionLen > MAX_OPTION_LEN) {
724             throw new IllegalArgumentException("DHCP option too long: "
725                     + optionLen + " vs. " + MAX_OPTION_LEN);
726         }
727 
728         buf.put(type);
729         buf.put((byte)(optionLen));
730 
731         for (Inet4Address addr : addrs) {
732             buf.put(addr.getAddress());
733         }
734     }
735 
736     /**
737      * Adds an optional parameter containing a short integer.
738      *
739      * <p>This method is a no-op if the value argument is null.
740      */
addTlv(ByteBuffer buf, byte type, @Nullable Short value)741     protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) {
742         if (value != null) {
743             buf.put(type);
744             buf.put((byte) 2);
745             buf.putShort(value.shortValue());
746         }
747     }
748 
749     /**
750      * Adds an optional parameter containing a simple integer.
751      *
752      * <p>This method is a no-op if the value argument is null.
753      */
addTlv(ByteBuffer buf, byte type, @Nullable Integer value)754     protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) {
755         if (value != null) {
756             buf.put(type);
757             buf.put((byte) 4);
758             buf.putInt(value.intValue());
759         }
760     }
761 
762     /**
763      * Adds an optional parameter containing an ASCII string.
764      *
765      * <p>This method is a no-op if the string argument is null.
766      */
addTlv(ByteBuffer buf, byte type, @Nullable String str)767     protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) {
768         if (str != null) {
769             try {
770                 addTlv(buf, type, str.getBytes("US-ASCII"));
771             } catch (UnsupportedEncodingException e) {
772                 throw new IllegalArgumentException("String is not US-ASCII: " + str);
773             }
774         }
775     }
776 
777     /**
778      * Adds the special end-of-optional-parameters indicator.
779      */
addTlvEnd(ByteBuffer buf)780     protected static void addTlvEnd(ByteBuffer buf) {
781         buf.put((byte) 0xFF);
782     }
783 
784     /**
785      * Get the DHCP Vendor Class Identifier.
786      *
787      * By default the vendor Id is "android-dhcp-<version>". The default value will be overwritten
788      * with the customized option value if any.
789      */
getVendorId(@ullable List<DhcpOption> customizedClientOptions)790     private static String getVendorId(@Nullable List<DhcpOption> customizedClientOptions) {
791         if (sTestOverrideVendorId != null) return sTestOverrideVendorId;
792 
793         String vendorId = "android-dhcp-" + Build.VERSION.RELEASE;
794         if (customizedClientOptions != null) {
795             for (DhcpOption option : customizedClientOptions) {
796                 if (option.type == DHCP_VENDOR_CLASS_ID) {
797                     vendorId = readAsciiString(option.value, false);
798                     break;
799                 }
800             }
801         }
802         return vendorId;
803     }
804 
805     /**
806      * Get the DHCP client hostname after transliteration.
807      */
808     @VisibleForTesting
getHostname()809     public String getHostname() {
810         if (mHostName == null && !isAtLeastR()) {
811             return SystemProperties.get("net.hostname");
812         }
813         return mHostName;
814     }
815 
816     /**
817      * Adds common client TLVs.
818      *
819      * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket
820      * methods to take them.
821      */
addCommonClientTlvs(ByteBuffer buf)822     protected void addCommonClientTlvs(ByteBuffer buf) {
823         addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
824         addTlv(buf, DHCP_VENDOR_CLASS_ID, mVendorId);
825         final String hn = getHostname();
826         if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn);
827     }
828 
829     /**
830      * Adds OEM's customized client TLVs, which will be appended before the End Tlv.
831      */
addCustomizedClientTlvs(ByteBuffer buf)832     protected void addCustomizedClientTlvs(ByteBuffer buf) {
833         if (mCustomizedClientOptions == null) return;
834         for (DhcpOption option : mCustomizedClientOptions) {
835             // A null value means the option should only be put into the PRL.
836             if (option.value == null) continue;
837             // The vendor class ID was already added by addCommonClientTlvs.
838             if (option.type == DHCP_VENDOR_CLASS_ID) continue;
839             addTlv(buf, option.type, option.value);
840         }
841     }
842 
843     // The common server TLVs are corresponding to the parameter request list from client.
addCommonServerTlvs(ByteBuffer buf)844     protected void addCommonServerTlvs(ByteBuffer buf) {
845         addTlv(buf, DHCP_LEASE_TIME, mLeaseTime);
846         if (mLeaseTime != null && mLeaseTime != INFINITE_LEASE) {
847             // The client should renew at 1/2 the lease-expiry interval
848             addTlv(buf, DHCP_RENEWAL_TIME, (int) (Integer.toUnsignedLong(mLeaseTime) / 2));
849             // Default rebinding time is set as below by RFC2131
850             addTlv(buf, DHCP_REBINDING_TIME,
851                     (int) (Integer.toUnsignedLong(mLeaseTime) * 875L / 1000L));
852         }
853         addTlv(buf, DHCP_SUBNET_MASK, mSubnetMask);
854         addTlv(buf, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
855         addTlv(buf, DHCP_ROUTER, mGateways);
856         addTlv(buf, DHCP_DNS_SERVER, mDnsServers);
857         addTlv(buf, DHCP_DOMAIN_NAME, mDomainName);
858         addTlv(buf, DHCP_HOST_NAME, mHostName);
859         addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo);
860         if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
861             addTlv(buf, DHCP_MTU, mMtu);
862         }
863         if (mIpv6OnlyWaitTime != null) {
864             addTlv(buf, DHCP_IPV6_ONLY_PREFERRED, (int) Integer.toUnsignedLong(mIpv6OnlyWaitTime));
865         }
866         if (mDmnSrchList != null && mDmnSrchList.size() > 0) {
867             // domain search list string is space separated.
868             String[] searchList = new String[mDmnSrchList.size()];
869             for (int i = 0; i < mDmnSrchList.size(); i++) {
870                 searchList[i] = mDmnSrchList.get(i);
871             }
872             final byte[] domains = DomainUtils.encode(searchList, true /* compression */);
873             addTlv(buf, DHCP_DOMAIN_SEARCHLIST, domains);
874         }
875         addTlv(buf, DHCP_CAPTIVE_PORTAL, mCaptivePortalUrl);
876     }
877 
878     /**
879      * Converts a MAC from an array of octets to an ASCII string.
880      */
macToString(byte[] mac)881     public static String macToString(byte[] mac) {
882         String macAddr = "";
883 
884         for (int i = 0; i < mac.length; i++) {
885             String hexString = "0" + Integer.toHexString(mac[i]);
886 
887             // substring operation grabs the last 2 digits: this
888             // allows signed bytes to be converted correctly.
889             macAddr += hexString.substring(hexString.length() - 2);
890 
891             if (i != (mac.length - 1)) {
892                 macAddr += ":";
893             }
894         }
895 
896         return macAddr;
897     }
898 
toString()899     public String toString() {
900         String macAddr = macToString(mClientMac);
901 
902         return macAddr;
903     }
904 
905     /**
906      * Reads a four-octet value from a ByteBuffer and construct
907      * an IPv4 address from that value.
908      */
readIpAddress(ByteBuffer packet)909     private static Inet4Address readIpAddress(ByteBuffer packet) {
910         Inet4Address result = null;
911         byte[] ipAddr = new byte[4];
912         packet.get(ipAddr);
913 
914         try {
915             result = (Inet4Address) Inet4Address.getByAddress(ipAddr);
916         } catch (UnknownHostException ex) {
917             // ipAddr is numeric, so this should not be
918             // triggered.  However, if it is, just nullify
919             result = null;
920         }
921 
922         return result;
923     }
924 
925     /**
926      * Reads a string of specified length from the buffer.
927      */
readAsciiString(@onNull final ByteBuffer buf, int byteCount, boolean nullOk)928     private static String readAsciiString(@NonNull final ByteBuffer buf, int byteCount,
929             boolean nullOk) {
930         final byte[] bytes = new byte[byteCount];
931         buf.get(bytes);
932         return readAsciiString(bytes, nullOk);
933     }
934 
readAsciiString(@onNull final byte[] payload, boolean nullOk)935     private static String readAsciiString(@NonNull final byte[] payload, boolean nullOk) {
936         final byte[] bytes = payload;
937         int length = bytes.length;
938         if (!nullOk) {
939             // Stop at the first null byte. This is because some DHCP options (e.g., the domain
940             // name) are passed to netd via FrameworkListener, which refuses arguments containing
941             // null bytes. We don't do this by default because vendorInfo is an opaque string which
942             // could in theory contain null bytes.
943             for (length = 0; length < bytes.length; length++) {
944                 if (bytes[length] == 0) {
945                     break;
946                 }
947             }
948         }
949         return new String(bytes, 0, length, StandardCharsets.US_ASCII);
950     }
951 
isPacketToOrFromClient(short udpSrcPort, short udpDstPort)952     private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
953         return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
954     }
955 
isPacketServerToServer(short udpSrcPort, short udpDstPort)956     private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) {
957         return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER);
958     }
959 
960     public static class ParseException extends Exception {
961         public final int errorCode;
ParseException(int errorCode, String msg, Object... args)962         public ParseException(int errorCode, String msg, Object... args) {
963             super(String.format(msg, args));
964             this.errorCode = errorCode;
965         }
966     }
967 
skipOption(ByteBuffer packet, int optionLen)968     private static int skipOption(ByteBuffer packet, int optionLen)
969             throws BufferUnderflowException {
970         int expectedLen = 0;
971         for (int i = 0; i < optionLen; i++) {
972             expectedLen++;
973             packet.get();
974         }
975         return expectedLen;
976     }
977 
shouldSkipOption(byte optionType, byte[] optionsToSkip)978     private static boolean shouldSkipOption(byte optionType, byte[] optionsToSkip) {
979         for (byte option : optionsToSkip) {
980             if (option == optionType) return true;
981         }
982         return false;
983     }
984 
985     /**
986      * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
987      * buffer may have an L2 encapsulation (which is the full EthernetII
988      * format starting with the source-address MAC) or an L3 encapsulation
989      * (which starts with the IP header).
990      * <br>
991      * A subset of the optional parameters are parsed and are stored
992      * in object fields.
993      */
994     @VisibleForTesting
decodeFullPacket(ByteBuffer packet, int pktType, byte[] optionsToSkip)995     static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType, byte[] optionsToSkip)
996             throws ParseException {
997         // bootp parameters
998         int transactionId;
999         short secs;
1000         Inet4Address clientIp;
1001         Inet4Address yourIp;
1002         Inet4Address nextIp;
1003         Inet4Address relayIp;
1004         byte[] clientMac;
1005         byte[] clientId = null;
1006         List<Inet4Address> dnsServers = new ArrayList<>();
1007         List<Inet4Address> gateways = new ArrayList<>();  // aka router
1008         ArrayList<String> dmnSrchList =  new ArrayList<>();
1009         Inet4Address serverIdentifier = null;
1010         Inet4Address netMask = null;
1011         String message = null;
1012         String vendorId = null;
1013         String vendorInfo = null;
1014         boolean rapidCommit = false;
1015         String captivePortalUrl = null;
1016         byte[] expectedParams = null;
1017         String hostName = null;
1018         String domainName = null;
1019         Inet4Address ipSrc = null;
1020         Inet4Address ipDst = null;
1021         Inet4Address bcAddr = null;
1022         Inet4Address requestedIp = null;
1023         String serverHostName;
1024         byte optionOverload = 0;
1025         byte[] userClass = null;
1026 
1027         // The following are all unsigned integers. Internally we store them as signed integers of
1028         // the same length because that way we're guaranteed that they can't be out of the range of
1029         // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
1030         // to cast it.
1031         Short mtu = null;
1032         Short maxMessageSize = null;
1033         Integer leaseTime = null;
1034         Integer T1 = null;
1035         Integer T2 = null;
1036         Integer ipv6OnlyWaitTime = null;
1037 
1038         // dhcp options
1039         byte dhcpType = (byte) 0xFF;
1040 
1041         packet.order(ByteOrder.BIG_ENDIAN);
1042 
1043         // check to see if we need to parse L2, IP, and UDP encaps
1044         if (pktType == ENCAP_L2) {
1045             if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
1046                 throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT,
1047                         "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
1048             }
1049 
1050             byte[] l2dst = new byte[6];
1051             byte[] l2src = new byte[6];
1052 
1053             packet.get(l2dst);
1054             packet.get(l2src);
1055 
1056             short l2type = packet.getShort();
1057 
1058             if (l2type != OsConstants.ETH_P_IP) {
1059                 throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE,
1060                         "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
1061             }
1062         }
1063 
1064         if (pktType <= ENCAP_L3) {
1065             if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
1066                 throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT,
1067                         "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
1068             }
1069 
1070             byte ipTypeAndLength = packet.get();
1071             int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
1072             if (ipVersion != 4) {
1073                 throw new ParseException(
1074                         DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
1075             }
1076 
1077             // System.out.println("ipType is " + ipType);
1078             byte ipDiffServicesField = packet.get();
1079             short ipTotalLength = packet.getShort();
1080             short ipIdentification = packet.getShort();
1081             byte ipFlags = packet.get();
1082             byte ipFragOffset = packet.get();
1083             byte ipTTL = packet.get();
1084             byte ipProto = packet.get();
1085             short ipChksm = packet.getShort();
1086 
1087             ipSrc = readIpAddress(packet);
1088             ipDst = readIpAddress(packet);
1089 
1090             if (ipProto != IP_TYPE_UDP) {
1091                 throw new ParseException(
1092                         DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
1093             }
1094 
1095             // Skip options. This cannot cause us to read beyond the end of the buffer because the
1096             // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
1097             // MIN_PACKET_LENGTH_L3.
1098             int optionWords = ((ipTypeAndLength & 0x0f) - 5);
1099             for (int i = 0; i < optionWords; i++) {
1100                 packet.getInt();
1101             }
1102 
1103             // assume UDP
1104             short udpSrcPort = packet.getShort();
1105             short udpDstPort = packet.getShort();
1106             short udpLen = packet.getShort();
1107             short udpChkSum = packet.getShort();
1108 
1109             // Only accept packets to or from the well-known client port (expressly permitting
1110             // packets from ports other than the well-known server port; http://b/24687559), and
1111             // server-to-server packets, e.g. for relays.
1112             if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
1113                 !isPacketServerToServer(udpSrcPort, udpDstPort)) {
1114                 // This should almost never happen because we use SO_ATTACH_FILTER on the packet
1115                 // socket to drop packets that don't have the right source ports. However, it's
1116                 // possible that a packet arrives between when the socket is bound and when the
1117                 // filter is set. http://b/26696823 .
1118                 throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT,
1119                         "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
1120             }
1121         }
1122 
1123         // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
1124         if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
1125             throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT,
1126                         "Invalid type or BOOTP packet too short, %d < %d",
1127                         packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
1128         }
1129 
1130         byte type = packet.get();
1131         byte hwType = packet.get();
1132         int addrLen = packet.get() & 0xff;
1133         byte hops = packet.get();
1134         transactionId = packet.getInt();
1135         secs = packet.getShort();
1136         short bootpFlags = packet.getShort();
1137         boolean broadcast = (bootpFlags & 0x8000) != 0;
1138         byte[] ipv4addr = new byte[4];
1139 
1140         try {
1141             packet.get(ipv4addr);
1142             clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
1143             packet.get(ipv4addr);
1144             yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
1145             packet.get(ipv4addr);
1146             nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
1147             packet.get(ipv4addr);
1148             relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
1149         } catch (UnknownHostException ex) {
1150             throw new ParseException(DhcpErrorEvent.L3_INVALID_IP,
1151                     "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
1152         }
1153 
1154         // Some DHCP servers have been known to announce invalid client hardware address values such
1155         // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
1156         // all but only checks that the interface MAC address matches the first bytes of the address
1157         // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
1158         // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
1159         // TODO: evaluate whether to make this test more liberal.
1160         if (addrLen > HWADDR_LEN) {
1161             addrLen = ETHER_BROADCAST.length;
1162         }
1163 
1164         clientMac = new byte[addrLen];
1165         packet.get(clientMac);
1166 
1167         // skip over address padding (16 octets allocated)
1168         packet.position(packet.position() + (16 - addrLen));
1169         serverHostName = readAsciiString(packet, 64, false);
1170         packet.position(packet.position() + 128);
1171 
1172         // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
1173         if (packet.remaining() < 4) {
1174             throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
1175         }
1176 
1177         int dhcpMagicCookie = packet.getInt();
1178         if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
1179             throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
1180                     "Bad magic cookie 0x%08x, should be 0x%08x",
1181                     dhcpMagicCookie, DHCP_MAGIC_COOKIE);
1182         }
1183 
1184         // parse options
1185         boolean notFinishedOptions = true;
1186 
1187         while ((packet.position() < packet.limit()) && notFinishedOptions) {
1188             final byte optionType = packet.get(); // cannot underflow because position < limit
1189             try {
1190                 if (optionType == DHCP_OPTION_END) {
1191                     notFinishedOptions = false;
1192                 } else if (optionType == DHCP_OPTION_PAD) {
1193                     // The pad option doesn't have a length field. Nothing to do.
1194                 } else {
1195                     int optionLen = packet.get() & 0xFF;
1196                     int expectedLen = 0;
1197 
1198                     if (shouldSkipOption(optionType, optionsToSkip)) {
1199                         skipOption(packet, optionLen);
1200                         continue;
1201                     }
1202 
1203                     switch(optionType) {
1204                         case DHCP_SUBNET_MASK:
1205                             netMask = readIpAddress(packet);
1206                             expectedLen = 4;
1207                             break;
1208                         case DHCP_ROUTER:
1209                             for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
1210                                 gateways.add(readIpAddress(packet));
1211                             }
1212                             break;
1213                         case DHCP_DNS_SERVER:
1214                             for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
1215                                 dnsServers.add(readIpAddress(packet));
1216                             }
1217                             break;
1218                         case DHCP_HOST_NAME:
1219                             expectedLen = optionLen;
1220                             hostName = readAsciiString(packet, optionLen, false);
1221                             break;
1222                         case DHCP_MTU:
1223                             expectedLen = 2;
1224                             mtu = packet.getShort();
1225                             break;
1226                         case DHCP_DOMAIN_NAME:
1227                             expectedLen = optionLen;
1228                             domainName = readAsciiString(packet, optionLen, false);
1229                             break;
1230                         case DHCP_BROADCAST_ADDRESS:
1231                             bcAddr = readIpAddress(packet);
1232                             expectedLen = 4;
1233                             break;
1234                         case DHCP_REQUESTED_IP:
1235                             requestedIp = readIpAddress(packet);
1236                             expectedLen = 4;
1237                             break;
1238                         case DHCP_LEASE_TIME:
1239                             leaseTime = Integer.valueOf(packet.getInt());
1240                             expectedLen = 4;
1241                             break;
1242                         case DHCP_MESSAGE_TYPE:
1243                             dhcpType = packet.get();
1244                             expectedLen = 1;
1245                             break;
1246                         case DHCP_SERVER_IDENTIFIER:
1247                             serverIdentifier = readIpAddress(packet);
1248                             expectedLen = 4;
1249                             break;
1250                         case DHCP_PARAMETER_LIST:
1251                             expectedParams = new byte[optionLen];
1252                             packet.get(expectedParams);
1253                             expectedLen = optionLen;
1254                             break;
1255                         case DHCP_MESSAGE:
1256                             expectedLen = optionLen;
1257                             message = readAsciiString(packet, optionLen, false);
1258                             break;
1259                         case DHCP_MAX_MESSAGE_SIZE:
1260                             expectedLen = 2;
1261                             maxMessageSize = Short.valueOf(packet.getShort());
1262                             break;
1263                         case DHCP_RENEWAL_TIME:
1264                             expectedLen = 4;
1265                             T1 = Integer.valueOf(packet.getInt());
1266                             break;
1267                         case DHCP_REBINDING_TIME:
1268                             expectedLen = 4;
1269                             T2 = Integer.valueOf(packet.getInt());
1270                             break;
1271                         case DHCP_VENDOR_CLASS_ID:
1272                             expectedLen = optionLen;
1273                             // Embedded nulls are safe as this does not get passed to netd.
1274                             vendorId = readAsciiString(packet, optionLen, true);
1275                             break;
1276                         case DHCP_CLIENT_IDENTIFIER: { // Client identifier
1277                             clientId = new byte[optionLen];
1278                             packet.get(clientId);
1279                             expectedLen = optionLen;
1280                         } break;
1281                         case DHCP_VENDOR_INFO:
1282                             expectedLen = optionLen;
1283                             // Embedded nulls are safe as this does not get passed to netd.
1284                             vendorInfo = readAsciiString(packet, optionLen, true);
1285                             break;
1286                         case DHCP_OPTION_OVERLOAD:
1287                             expectedLen = 1;
1288                             optionOverload = packet.get();
1289                             optionOverload &= OPTION_OVERLOAD_BOTH;
1290                             break;
1291                         case DHCP_USER_CLASS:
1292                             userClass = new byte[optionLen];
1293                             packet.get(userClass);
1294                             expectedLen = optionLen;
1295                             break;
1296                         case DHCP_RAPID_COMMIT:
1297                             expectedLen = 0;
1298                             rapidCommit = true;
1299                             break;
1300                         case DHCP_CAPTIVE_PORTAL:
1301                             expectedLen = optionLen;
1302                             captivePortalUrl = readAsciiString(packet, optionLen, true);
1303                             break;
1304                         case DHCP_IPV6_ONLY_PREFERRED:
1305                             if (optionLen == 4) {
1306                                 expectedLen = optionLen;
1307                                 ipv6OnlyWaitTime = Integer.valueOf(packet.getInt());
1308                             } else {
1309                                 // rfc8925#section-3.1: The client MUST ignore the IPv6-Only
1310                                 // Preferred option if the length field value is not 4.
1311                                 expectedLen = skipOption(packet, optionLen);
1312                             }
1313                             break;
1314                         case DHCP_DOMAIN_SEARCHLIST:
1315                             // TODO: should support multiple options(i.e. length > 255)?
1316                             expectedLen = optionLen;
1317                             final byte[] bytes = new byte[expectedLen];
1318                             packet.get(bytes);
1319                             final ByteBuffer buf = ByteBuffer.wrap(bytes);
1320                             dmnSrchList = DomainUtils.decode(buf, true /* compression */);
1321                             break;
1322                         default:
1323                             expectedLen = skipOption(packet, optionLen);
1324                     }
1325 
1326                     if (expectedLen != optionLen) {
1327                         final int errorCode = DhcpErrorEvent.errorCodeWithOption(
1328                                 DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
1329                         throw new ParseException(errorCode,
1330                                 "Invalid length %d for option %d, expected %d",
1331                                 optionLen, optionType, expectedLen);
1332                     }
1333                 }
1334             } catch (BufferUnderflowException e) {
1335                 final int errorCode = DhcpErrorEvent.errorCodeWithOption(
1336                         DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
1337                 throw new ParseException(errorCode, "BufferUnderflowException");
1338             }
1339         }
1340 
1341         DhcpPacket newPacket;
1342 
1343         switch(dhcpType) {
1344             case (byte) 0xFF:
1345                 throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
1346                         "No DHCP message type option");
1347             case DHCP_MESSAGE_TYPE_DISCOVER:
1348                 newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac,
1349                         broadcast, ipSrc, rapidCommit);
1350                 break;
1351             case DHCP_MESSAGE_TYPE_OFFER:
1352                 newPacket = new DhcpOfferPacket(
1353                     transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
1354                 break;
1355             case DHCP_MESSAGE_TYPE_REQUEST:
1356                 newPacket = new DhcpRequestPacket(
1357                     transactionId, secs, clientIp, relayIp, clientMac, broadcast);
1358                 break;
1359             case DHCP_MESSAGE_TYPE_DECLINE:
1360                 newPacket = new DhcpDeclinePacket(
1361                     transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, requestedIp,
1362                     serverIdentifier);
1363                 break;
1364             case DHCP_MESSAGE_TYPE_ACK:
1365                 newPacket = new DhcpAckPacket(
1366                     transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac,
1367                     rapidCommit);
1368                 break;
1369             case DHCP_MESSAGE_TYPE_NAK:
1370                 newPacket = new DhcpNakPacket(
1371                         transactionId, secs, relayIp, clientMac, broadcast);
1372                 break;
1373             case DHCP_MESSAGE_TYPE_RELEASE:
1374                 if (serverIdentifier == null) {
1375                     throw new ParseException(DhcpErrorEvent.MISC_ERROR,
1376                             "DHCPRELEASE without server identifier");
1377                 }
1378                 newPacket = new DhcpReleasePacket(
1379                         transactionId, serverIdentifier, clientIp, relayIp, clientMac);
1380                 break;
1381             default:
1382                 throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE,
1383                         "Unimplemented DHCP type %d", dhcpType);
1384         }
1385 
1386         newPacket.mBroadcastAddress = bcAddr;
1387         newPacket.mClientId = clientId;
1388         newPacket.mDnsServers = dnsServers;
1389         newPacket.mGateways = gateways;
1390         newPacket.mHostName = hostName;
1391         newPacket.mLeaseTime = leaseTime;
1392         newPacket.mMessage = message;
1393         newPacket.mMtu = mtu;
1394         newPacket.mRequestedIp = requestedIp;
1395         newPacket.mRequestedParams = expectedParams;
1396         newPacket.mServerIdentifier = serverIdentifier;
1397         newPacket.mSubnetMask = netMask;
1398         newPacket.mMaxMessageSize = maxMessageSize;
1399         newPacket.mT1 = T1;
1400         newPacket.mT2 = T2;
1401         newPacket.mVendorId = vendorId;
1402         newPacket.mVendorInfo = vendorInfo;
1403         newPacket.mCaptivePortalUrl = captivePortalUrl;
1404         newPacket.mIpv6OnlyWaitTime = ipv6OnlyWaitTime;
1405         newPacket.mUserClass = userClass;
1406         if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) {
1407             newPacket.mServerHostName = serverHostName;
1408         } else {
1409             newPacket.mServerHostName = "";
1410         }
1411         // Domain suffixes in the search list are concatenated to domain name with space separated,
1412         // which will be set to DnsResolver via LinkProperties.
1413         newPacket.mDmnSrchList = dmnSrchList;
1414         newPacket.mDomainName = domainName;
1415         return newPacket;
1416     }
1417 
1418     /**
1419      * Parse a packet from an array of bytes, stopping at the given length.
1420      */
decodeFullPacket(byte[] packet, int length, int pktType, byte[] optionsToSkip)1421     public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType,
1422             byte[] optionsToSkip) throws ParseException {
1423         ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
1424         try {
1425             return decodeFullPacket(buffer, pktType, optionsToSkip);
1426         } catch (ParseException e) {
1427             throw e;
1428         } catch (Exception e) {
1429             throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
1430         }
1431     }
1432 
1433     /**
1434      * Parse a packet from an array of bytes, stopping at the given length.
1435      */
decodeFullPacket(byte[] packet, int length, int pktType)1436     public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
1437             throws ParseException {
1438         return decodeFullPacket(packet, length, pktType, new byte[0]);
1439     }
1440 
1441     /**
1442      *  Construct a DhcpResults object from a DHCP reply packet.
1443      */
toDhcpResults()1444     public DhcpResults toDhcpResults() {
1445         Inet4Address ipAddress = mYourIp;
1446         if (ipAddress.equals(IPV4_ADDR_ANY)) {
1447             ipAddress = mClientIp;
1448             if (ipAddress.equals(IPV4_ADDR_ANY)) {
1449                 return null;
1450             }
1451         }
1452 
1453         int prefixLength;
1454         if (mSubnetMask != null) {
1455             try {
1456                 prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask);
1457             } catch (IllegalArgumentException e) {
1458                 // Non-contiguous netmask.
1459                 return null;
1460             }
1461         } else {
1462             prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress);
1463         }
1464 
1465         DhcpResults results = new DhcpResults();
1466         try {
1467             results.ipAddress = new LinkAddress(ipAddress, prefixLength);
1468         } catch (IllegalArgumentException e) {
1469             return null;
1470         }
1471 
1472         if (mGateways.size() > 0) {
1473             results.gateway = mGateways.get(0);
1474         }
1475 
1476         results.dnsServers.addAll(mDnsServers);
1477         results.domains = mDomainName;
1478         results.serverAddress = mServerIdentifier;
1479         results.vendorInfo = mVendorInfo;
1480         results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
1481         results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
1482         results.serverHostName = mServerHostName;
1483         results.captivePortalApiUrl = mCaptivePortalUrl;
1484         // Add the check before setting it
1485         if (mDmnSrchList != null && mDmnSrchList.size() > 0) {
1486             results.dmnsrchList.addAll(mDmnSrchList);
1487         }
1488         return results;
1489     }
1490 
1491     /**
1492      * Returns the parsed lease time, in milliseconds, or 0 for infinite.
1493      */
getLeaseTimeMillis(int defaultMinimumLease)1494     public long getLeaseTimeMillis(int defaultMinimumLease) {
1495         // dhcpcd treats the lack of a lease time option as an infinite lease.
1496         if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) {
1497             return 0;
1498         } else if (0 <= mLeaseTime && mLeaseTime < defaultMinimumLease) {
1499             return defaultMinimumLease * 1000L;
1500         } else {
1501             return (mLeaseTime & 0xffffffffL) * 1000;
1502         }
1503     }
1504 
1505     /**
1506      * Returns the IPv6-only wait time, in milliseconds, or -1 if the option is not present.
1507      */
getIpv6OnlyWaitTimeMillis()1508     public long getIpv6OnlyWaitTimeMillis() {
1509         if (mIpv6OnlyWaitTime == null) return V6ONLY_PREFERRED_ABSENCE;
1510         return Math.max(MIN_V6ONLY_WAIT_MS, Integer.toUnsignedLong(mIpv6OnlyWaitTime) * 1000);
1511     }
1512 
1513     /**
1514      * Builds a DHCP-DISCOVER packet from the required specified parameters.
1515      */
buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit, String hostname, List<DhcpOption> options)1516     public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
1517             short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams,
1518             boolean rapidCommit, String hostname, List<DhcpOption> options) {
1519         DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */,
1520                 clientMac, broadcast, INADDR_ANY /* srcIp */, rapidCommit);
1521         pkt.mRequestedParams = expectedParams;
1522         pkt.mHostName = hostname;
1523         pkt.mCustomizedClientOptions = options;
1524         pkt.mVendorId = getVendorId(options);
1525         return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
1526     }
1527 
1528     /**
1529      * Builds a DHCP-DISCOVER packet from the required specified parameters.
1530      *
1531      * TODO: remove this method when automerger to mainline-prod is running.
1532      */
buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit, String hostname)1533     public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
1534             short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams,
1535             boolean rapidCommit, String hostname) {
1536         return buildDiscoverPacket(encap, transactionId, secs, clientMac, broadcast,
1537                 expectedParams, rapidCommit, hostname, new ArrayList<DhcpOption>());
1538     }
1539 
1540     /**
1541      * Builds a DHCP-OFFER packet from the required specified parameters.
1542      */
buildOfferPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, String captivePortalUrl, Integer ipv6OnlyWaitTime, List<String> domainSearchList)1543     public static ByteBuffer buildOfferPacket(int encap, int transactionId,
1544             boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
1545             Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
1546             Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
1547             Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
1548             short mtu, String captivePortalUrl, Integer ipv6OnlyWaitTime,
1549             List<String> domainSearchList) {
1550         DhcpPacket pkt = new DhcpOfferPacket(
1551                 transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
1552                 INADDR_ANY /* clientIp */, yourIp, mac);
1553         pkt.mGateways = gateways;
1554         pkt.mDnsServers = dnsServers;
1555         pkt.mLeaseTime = timeout;
1556         pkt.mDomainName = domainName;
1557         pkt.mHostName = hostname;
1558         pkt.mServerIdentifier = dhcpServerIdentifier;
1559         pkt.mSubnetMask = netMask;
1560         pkt.mBroadcastAddress = bcAddr;
1561         pkt.mMtu = mtu;
1562         pkt.mCaptivePortalUrl = captivePortalUrl;
1563         if (domainSearchList != null) {
1564             pkt.mDmnSrchList = new ArrayList<>(domainSearchList);
1565         }
1566         if (metered) {
1567             pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
1568         }
1569         if (ipv6OnlyWaitTime != null) {
1570             pkt.mIpv6OnlyWaitTime = ipv6OnlyWaitTime;
1571         }
1572         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
1573     }
1574 
1575     /**
1576      * Builds a DHCP-OFFER packet from the required specified parameters.
1577      */
buildOfferPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, String captivePortalUrl)1578     public static ByteBuffer buildOfferPacket(int encap, int transactionId,
1579             boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
1580             Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
1581             Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
1582             Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
1583             short mtu, String captivePortalUrl) {
1584         return buildOfferPacket(encap, transactionId, broadcast, serverIpAddr, relayIp, yourIp,
1585                 mac, timeout, netMask, bcAddr, gateways, dnsServers, dhcpServerIdentifier,
1586                 domainName, hostname, metered, mtu, captivePortalUrl, null /* V6ONLY_WAIT */,
1587                 null /* domainSearchList */);
1588     }
1589 
1590     /**
1591      * Builds a DHCP-ACK packet from the required specified parameters.
1592      */
buildAckPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, boolean rapidCommit, String captivePortalUrl, Integer ipv6OnlyWaitTime, List<String> domainSearchList)1593     public static ByteBuffer buildAckPacket(int encap, int transactionId,
1594             boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp,
1595             Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
1596             Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
1597             Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
1598             short mtu, boolean rapidCommit, String captivePortalUrl, Integer ipv6OnlyWaitTime,
1599             List<String> domainSearchList) {
1600         DhcpPacket pkt = new DhcpAckPacket(
1601                 transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
1602                 mac, rapidCommit);
1603         pkt.mGateways = gateways;
1604         pkt.mDnsServers = dnsServers;
1605         pkt.mLeaseTime = timeout;
1606         pkt.mDomainName = domainName;
1607         pkt.mHostName = hostname;
1608         pkt.mSubnetMask = netMask;
1609         pkt.mServerIdentifier = dhcpServerIdentifier;
1610         pkt.mBroadcastAddress = bcAddr;
1611         pkt.mMtu = mtu;
1612         pkt.mCaptivePortalUrl = captivePortalUrl;
1613         if (domainSearchList != null) {
1614             pkt.mDmnSrchList = new ArrayList<>(domainSearchList);
1615         }
1616         if (metered) {
1617             pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
1618         }
1619         if (ipv6OnlyWaitTime != null) {
1620             pkt.mIpv6OnlyWaitTime = ipv6OnlyWaitTime;
1621         }
1622         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
1623     }
1624 
1625     /**
1626      * Builds a DHCP-ACK packet from the required specified parameters.
1627      */
buildAckPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, boolean rapidCommit, String captivePortalUrl)1628     public static ByteBuffer buildAckPacket(int encap, int transactionId,
1629             boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp,
1630             Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
1631             Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
1632             Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
1633             short mtu, boolean rapidCommit, String captivePortalUrl) {
1634         return buildAckPacket(encap, transactionId, broadcast, serverIpAddr, relayIp, yourIp,
1635                 requestClientIp, mac, timeout, netMask, bcAddr, gateways, dnsServers,
1636                 dhcpServerIdentifier, domainName, hostname, metered, mtu, rapidCommit,
1637                 captivePortalUrl, null /* V6ONLY_WAIT */, null /* domainSearchList */);
1638     }
1639 
1640     /**
1641      * Builds a DHCP-NAK packet from the required specified parameters.
1642      */
buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, Inet4Address relayIp, byte[] mac, boolean broadcast, String message)1643     public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr,
1644             Inet4Address relayIp, byte[] mac, boolean broadcast, String message) {
1645         DhcpPacket pkt = new DhcpNakPacket(
1646                 transactionId, (short) 0, relayIp, mac, broadcast);
1647         pkt.mMessage = message;
1648         pkt.mServerIdentifier = serverIpAddr;
1649         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
1650     }
1651 
1652     /**
1653      * Builds a DHCP-REQUEST packet from the required specified parameters.
1654      */
buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName, List<DhcpOption> options)1655     public static ByteBuffer buildRequestPacket(int encap,
1656             int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
1657             byte[] clientMac, Inet4Address requestedIpAddress,
1658             Inet4Address serverIdentifier, byte[] requestedParams, String hostName,
1659             List<DhcpOption> options) {
1660         DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
1661                 INADDR_ANY /* relayIp */, clientMac, broadcast);
1662         pkt.mRequestedIp = requestedIpAddress;
1663         pkt.mServerIdentifier = serverIdentifier;
1664         pkt.mHostName = hostName;
1665         pkt.mRequestedParams = requestedParams;
1666         pkt.mCustomizedClientOptions = options;
1667         pkt.mVendorId = getVendorId(options);
1668         ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
1669         return result;
1670     }
1671 
1672     /**
1673      * Builds a DHCP-REQUEST packet from the required specified parameters.
1674      *
1675      * TODO: remove this method when automerger to mainline-prod is running.
1676      */
buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName)1677     public static ByteBuffer buildRequestPacket(int encap,
1678             int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
1679             byte[] clientMac, Inet4Address requestedIpAddress,
1680             Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
1681         return buildRequestPacket(encap, transactionId, secs, clientIp, broadcast, clientMac,
1682                 requestedIpAddress, serverIdentifier, requestedParams, hostName,
1683                 new ArrayList<DhcpOption>());
1684     }
1685 
1686     /**
1687      * Builds a DHCP-DECLINE packet from the required specified parameters.
1688      */
buildDeclinePacket(int encap, int transactionId, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier)1689     public static ByteBuffer buildDeclinePacket(int encap, int transactionId, byte[] clientMac,
1690             Inet4Address requestedIpAddress, Inet4Address serverIdentifier) {
1691         DhcpPacket pkt = new DhcpDeclinePacket(transactionId, (short) 0 /* secs */,
1692                 INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */, INADDR_ANY /* nextIp */,
1693                 INADDR_ANY /* relayIp */, clientMac, requestedIpAddress, serverIdentifier);
1694         ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
1695         return result;
1696     }
1697 }
1698