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