blob: 317a9b4faba4b43e9dd8fd3fa6eb9ee63a442def [file] [log] [blame]
Stan Chesnutt7da02ad2010-12-14 09:49:26 -08001package android.net.dhcp;
2
3import android.util.Log;
4
5import java.io.UnsupportedEncodingException;
6import java.net.InetAddress;
7import java.net.UnknownHostException;
8import java.nio.ByteBuffer;
9import java.nio.ByteOrder;
Elliott Hughesd396a442013-06-28 16:24:48 -070010import java.nio.charset.StandardCharsets;
Stan Chesnutt7da02ad2010-12-14 09:49:26 -080011import java.nio.ShortBuffer;
12
13import java.util.ArrayList;
14import java.util.List;
15
16/**
17 * Defines basic data and operations needed to build and use packets for the
18 * DHCP protocol. Subclasses create the specific packets used at each
19 * stage of the negotiation.
20 */
21abstract class DhcpPacket {
22 protected static final String TAG = "DhcpPacket";
23
24 /**
25 * Packet encapsulations.
26 */
27 public static final int ENCAP_L2 = 0; // EthernetII header included
28 public static final int ENCAP_L3 = 1; // IP/UDP header included
29 public static final int ENCAP_BOOTP = 2; // BOOTP contents only
30
31 /**
32 * IP layer definitions.
33 */
34 private static final byte IP_TYPE_UDP = (byte) 0x11;
35
36 /**
37 * IP: Version 4, Header Length 20 bytes
38 */
39 private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
40
41 /**
42 * IP: Flags 0, Fragment Offset 0, Don't Fragment
43 */
44 private static final short IP_FLAGS_OFFSET = (short) 0x4000;
45
46 /**
47 * IP: TOS
48 */
49 private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
50
51 /**
52 * IP: TTL -- use default 64 from RFC1340
53 */
54 private static final byte IP_TTL = (byte) 0x40;
55
56 /**
57 * The client DHCP port.
58 */
59 static final short DHCP_CLIENT = (short) 68;
60
61 /**
62 * The server DHCP port.
63 */
64 static final short DHCP_SERVER = (short) 67;
65
66 /**
67 * The message op code indicating a request from a client.
68 */
69 protected static final byte DHCP_BOOTREQUEST = (byte) 1;
70
71 /**
72 * The message op code indicating a response from the server.
73 */
74 protected static final byte DHCP_BOOTREPLY = (byte) 2;
75
76 /**
77 * The code type used to identify an Ethernet MAC address in the
78 * Client-ID field.
79 */
80 protected static final byte CLIENT_ID_ETHER = (byte) 1;
81
82 /**
83 * The maximum length of a packet that can be constructed.
84 */
85 protected static final int MAX_LENGTH = 1500;
86
87 /**
88 * DHCP Optional Type: DHCP Subnet Mask
89 */
90 protected static final byte DHCP_SUBNET_MASK = 1;
91 protected InetAddress mSubnetMask;
92
93 /**
94 * DHCP Optional Type: DHCP Router
95 */
96 protected static final byte DHCP_ROUTER = 3;
97 protected InetAddress mGateway;
98
99 /**
100 * DHCP Optional Type: DHCP DNS Server
101 */
102 protected static final byte DHCP_DNS_SERVER = 6;
103 protected List<InetAddress> mDnsServers;
104
105 /**
106 * DHCP Optional Type: DHCP Host Name
107 */
108 protected static final byte DHCP_HOST_NAME = 12;
109 protected String mHostName;
110
111 /**
112 * DHCP Optional Type: DHCP DOMAIN NAME
113 */
114 protected static final byte DHCP_DOMAIN_NAME = 15;
115 protected String mDomainName;
116
117 /**
118 * DHCP Optional Type: DHCP BROADCAST ADDRESS
119 */
120 protected static final byte DHCP_BROADCAST_ADDRESS = 28;
121 protected InetAddress mBroadcastAddress;
122
123 /**
124 * DHCP Optional Type: DHCP Requested IP Address
125 */
126 protected static final byte DHCP_REQUESTED_IP = 50;
127 protected InetAddress mRequestedIp;
128
129 /**
130 * DHCP Optional Type: DHCP Lease Time
131 */
132 protected static final byte DHCP_LEASE_TIME = 51;
133 protected Integer mLeaseTime;
134
135 /**
136 * DHCP Optional Type: DHCP Message Type
137 */
138 protected static final byte DHCP_MESSAGE_TYPE = 53;
139 // the actual type values
140 protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
141 protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
142 protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
143 protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
144 protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
145 protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
146 protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
147
148 /**
149 * DHCP Optional Type: DHCP Server Identifier
150 */
151 protected static final byte DHCP_SERVER_IDENTIFIER = 54;
152 protected InetAddress mServerIdentifier;
153
154 /**
155 * DHCP Optional Type: DHCP Parameter List
156 */
157 protected static final byte DHCP_PARAMETER_LIST = 55;
158 protected byte[] mRequestedParams;
159
160 /**
161 * DHCP Optional Type: DHCP MESSAGE
162 */
163 protected static final byte DHCP_MESSAGE = 56;
164 protected String mMessage;
165
166 /**
167 * DHCP Optional Type: DHCP Renewal Time Value
168 */
169 protected static final byte DHCP_RENEWAL_TIME = 58;
170
171 /**
172 * DHCP Optional Type: Vendor Class Identifier
173 */
174 protected static final byte DHCP_VENDOR_CLASS_ID = 60;
175
176 /**
177 * DHCP Optional Type: DHCP Client Identifier
178 */
179 protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
180
181 /**
182 * The transaction identifier used in this particular DHCP negotiation
183 */
184 protected final int mTransId;
185
186 /**
187 * The IP address of the client host. This address is typically
188 * proposed by the client (from an earlier DHCP negotiation) or
189 * supplied by the server.
190 */
191 protected final InetAddress mClientIp;
192 protected final InetAddress mYourIp;
193 private final InetAddress mNextIp;
194 private final InetAddress mRelayIp;
195
196 /**
197 * Does the client request a broadcast response?
198 */
199 protected boolean mBroadcast;
200
201 /**
202 * The six-octet MAC of the client.
203 */
204 protected final byte[] mClientMac;
205
206 /**
207 * Asks the packet object to signal the next operation in the DHCP
208 * protocol. The available actions are methods defined in the
209 * DhcpStateMachine interface.
210 */
211 public abstract void doNextOp(DhcpStateMachine stateMachine);
212
213 /**
214 * Asks the packet object to create a ByteBuffer serialization of
215 * the packet for transmission.
216 */
217 public abstract ByteBuffer buildPacket(int encap, short destUdp,
218 short srcUdp);
219
220 /**
221 * Allows the concrete class to fill in packet-type-specific details,
222 * typically optional parameters at the end of the packet.
223 */
224 abstract void finishPacket(ByteBuffer buffer);
225
226 protected DhcpPacket(int transId, InetAddress clientIp, InetAddress yourIp,
227 InetAddress nextIp, InetAddress relayIp,
228 byte[] clientMac, boolean broadcast) {
229 mTransId = transId;
230 mClientIp = clientIp;
231 mYourIp = yourIp;
232 mNextIp = nextIp;
233 mRelayIp = relayIp;
234 mClientMac = clientMac;
235 mBroadcast = broadcast;
236 }
237
238 /**
239 * Returns the transaction ID.
240 */
241 public int getTransactionId() {
242 return mTransId;
243 }
244
245 /**
246 * Creates a new L3 packet (including IP header) containing the
247 * DHCP udp packet. This method relies upon the delegated method
248 * finishPacket() to insert the per-packet contents.
249 */
250 protected void fillInPacket(int encap, InetAddress destIp,
251 InetAddress srcIp, short destUdp, short srcUdp, ByteBuffer buf,
252 byte requestCode, boolean broadcast) {
253 byte[] destIpArray = destIp.getAddress();
254 byte[] srcIpArray = srcIp.getAddress();
255 int ipLengthOffset = 0;
256 int ipChecksumOffset = 0;
257 int endIpHeader = 0;
258 int udpHeaderOffset = 0;
259 int udpLengthOffset = 0;
260 int udpChecksumOffset = 0;
261
262 buf.clear();
263 buf.order(ByteOrder.BIG_ENDIAN);
264
265 // if a full IP packet needs to be generated, put the IP & UDP
266 // headers in place, and pre-populate with artificial values
267 // needed to seed the IP checksum.
268 if (encap == ENCAP_L3) {
269 // fake IP header, used in the IP-header checksum
270 buf.put(IP_VERSION_HEADER_LEN);
271 buf.put(IP_TOS_LOWDELAY); // tos: IPTOS_LOWDELAY
272 ipLengthOffset = buf.position();
273 buf.putShort((short)0); // length
274 buf.putShort((short)0); // id
275 buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment
276 buf.put(IP_TTL); // TTL: use default 64 from RFC1340
277 buf.put(IP_TYPE_UDP);
278 ipChecksumOffset = buf.position();
279 buf.putShort((short) 0); // checksum
280
281 buf.put(srcIpArray);
282 buf.put(destIpArray);
283 endIpHeader = buf.position();
284
285 // UDP header
286 udpHeaderOffset = buf.position();
287 buf.putShort(srcUdp);
288 buf.putShort(destUdp);
289 udpLengthOffset = buf.position();
290 buf.putShort((short) 0); // length
291 udpChecksumOffset = buf.position();
292 buf.putShort((short) 0); // UDP checksum -- initially zero
293 }
294
295 // DHCP payload
296 buf.put(requestCode);
297 buf.put((byte) 1); // Hardware Type: Ethernet
298 buf.put((byte) mClientMac.length); // Hardware Address Length
299 buf.put((byte) 0); // Hop Count
300 buf.putInt(mTransId); // Transaction ID
301 buf.putShort((short) 0); // Elapsed Seconds
302
303 if (broadcast) {
304 buf.putShort((short) 0x8000); // Flags
305 } else {
306 buf.putShort((short) 0x0000); // Flags
307 }
308
309 buf.put(mClientIp.getAddress());
310 buf.put(mYourIp.getAddress());
311 buf.put(mNextIp.getAddress());
312 buf.put(mRelayIp.getAddress());
313 buf.put(mClientMac);
314 buf.position(buf.position() +
315 (16 - mClientMac.length) // pad addr to 16 bytes
316 + 64 // empty server host name (64 bytes)
317 + 128); // empty boot file name (128 bytes)
318 buf.putInt(0x63825363); // magic number
319 finishPacket(buf);
320
321 // round up to an even number of octets
322 if ((buf.position() & 1) == 1) {
323 buf.put((byte) 0);
324 }
325
326 // If an IP packet is being built, the IP & UDP checksums must be
327 // computed.
328 if (encap == ENCAP_L3) {
329 // fix UDP header: insert length
330 short udpLen = (short)(buf.position() - udpHeaderOffset);
331 buf.putShort(udpLengthOffset, udpLen);
332 // fix UDP header: checksum
333 // checksum for UDP at udpChecksumOffset
334 int udpSeed = 0;
335
336 // apply IPv4 pseudo-header. Read IP address src and destination
337 // values from the IP header and accumulate checksum.
338 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2));
339 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4));
340 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6));
341 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8));
342
343 // accumulate extra data for the pseudo-header
344 udpSeed += IP_TYPE_UDP;
345 udpSeed += udpLen;
346 // and compute UDP checksum
347 buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed,
348 udpHeaderOffset,
349 buf.position()));
350 // fix IP header: insert length
351 buf.putShort(ipLengthOffset, (short)buf.position());
352 // fixup IP-header checksum
353 buf.putShort(ipChecksumOffset,
354 (short) checksum(buf, 0, 0, endIpHeader));
355 }
356 }
357
358 /**
359 * Converts a signed short value to an unsigned int value. Needed
360 * because Java does not have unsigned types.
361 */
362 private int intAbs(short v) {
363 if (v < 0) {
364 int r = v + 65536;
365 return r;
366 } else {
367 return(v);
368 }
369 }
370
371 /**
372 * Performs an IP checksum (used in IP header and across UDP
373 * payload) on the specified portion of a ByteBuffer. The seed
374 * allows the checksum to commence with a specified value.
375 */
376 private int checksum(ByteBuffer buf, int seed, int start, int end) {
377 int sum = seed;
378 int bufPosition = buf.position();
379
380 // set position of original ByteBuffer, so that the ShortBuffer
381 // will be correctly initialized
382 buf.position(start);
383 ShortBuffer shortBuf = buf.asShortBuffer();
384
385 // re-set ByteBuffer position
386 buf.position(bufPosition);
387
388 short[] shortArray = new short[(end - start) / 2];
389 shortBuf.get(shortArray);
390
391 for (short s : shortArray) {
392 sum += intAbs(s);
393 }
394
395 start += shortArray.length * 2;
396
397 // see if a singleton byte remains
398 if (end != start) {
399 short b = buf.get(start);
400
401 // make it unsigned
402 if (b < 0) {
403 b += 256;
404 }
405
406 sum += b * 256;
407 }
408
409 sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF);
410 sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF);
411 int negated = ~sum;
412 return intAbs((short) negated);
413 }
414
415 /**
416 * Adds an optional parameter containing a single byte value.
417 */
418 protected void addTlv(ByteBuffer buf, byte type, byte value) {
419 buf.put(type);
420 buf.put((byte) 1);
421 buf.put(value);
422 }
423
424 /**
425 * Adds an optional parameter containing an array of bytes.
426 */
427 protected void addTlv(ByteBuffer buf, byte type, byte[] payload) {
428 if (payload != null) {
429 buf.put(type);
430 buf.put((byte) payload.length);
431 buf.put(payload);
432 }
433 }
434
435 /**
436 * Adds an optional parameter containing an IP address.
437 */
438 protected void addTlv(ByteBuffer buf, byte type, InetAddress addr) {
439 if (addr != null) {
440 addTlv(buf, type, addr.getAddress());
441 }
442 }
443
444 /**
445 * Adds an optional parameter containing a list of IP addresses.
446 */
447 protected void addTlv(ByteBuffer buf, byte type, List<InetAddress> addrs) {
448 if (addrs != null && addrs.size() > 0) {
449 buf.put(type);
450 buf.put((byte)(4 * addrs.size()));
451
452 for (InetAddress addr : addrs) {
453 buf.put(addr.getAddress());
454 }
455 }
456 }
457
458 /**
459 * Adds an optional parameter containing a simple integer
460 */
461 protected void addTlv(ByteBuffer buf, byte type, Integer value) {
462 if (value != null) {
463 buf.put(type);
464 buf.put((byte) 4);
465 buf.putInt(value.intValue());
466 }
467 }
468
469 /**
470 * Adds an optional parameter containing and ASCII string.
471 */
472 protected void addTlv(ByteBuffer buf, byte type, String str) {
473 if (str != null) {
474 buf.put(type);
475 buf.put((byte) str.length());
476
477 for (int i = 0; i < str.length(); i++) {
478 buf.put((byte) str.charAt(i));
479 }
480 }
481 }
482
483 /**
484 * Adds the special end-of-optional-parameters indicator.
485 */
486 protected void addTlvEnd(ByteBuffer buf) {
487 buf.put((byte) 0xFF);
488 }
489
490 /**
491 * Converts a MAC from an array of octets to an ASCII string.
492 */
493 public static String macToString(byte[] mac) {
494 String macAddr = "";
495
496 for (int i = 0; i < mac.length; i++) {
497 String hexString = "0" + Integer.toHexString(mac[i]);
498
499 // substring operation grabs the last 2 digits: this
500 // allows signed bytes to be converted correctly.
501 macAddr += hexString.substring(hexString.length() - 2);
502
503 if (i != (mac.length - 1)) {
504 macAddr += ":";
505 }
506 }
507
508 return macAddr;
509 }
510
511 public String toString() {
512 String macAddr = macToString(mClientMac);
513
514 return macAddr;
515 }
516
517 /**
518 * Reads a four-octet value from a ByteBuffer and construct
519 * an IPv4 address from that value.
520 */
521 private static InetAddress readIpAddress(ByteBuffer packet) {
522 InetAddress result = null;
523 byte[] ipAddr = new byte[4];
524 packet.get(ipAddr);
525
526 try {
527 result = InetAddress.getByAddress(ipAddr);
528 } catch (UnknownHostException ex) {
529 // ipAddr is numeric, so this should not be
530 // triggered. However, if it is, just nullify
531 result = null;
532 }
533
534 return result;
535 }
536
537 /**
538 * Reads a string of specified length from the buffer.
539 */
540 private static String readAsciiString(ByteBuffer buf, int byteCount) {
541 byte[] bytes = new byte[byteCount];
542 buf.get(bytes);
Elliott Hughesd396a442013-06-28 16:24:48 -0700543 return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
Stan Chesnutt7da02ad2010-12-14 09:49:26 -0800544 }
545
546 /**
547 * Creates a concrete DhcpPacket from the supplied ByteBuffer. The
548 * buffer may have an L2 encapsulation (which is the full EthernetII
549 * format starting with the source-address MAC) or an L3 encapsulation
550 * (which starts with the IP header).
551 * <br>
552 * A subset of the optional parameters are parsed and are stored
553 * in object fields.
554 */
555 public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType)
556 {
557 // bootp parameters
558 int transactionId;
559 InetAddress clientIp;
560 InetAddress yourIp;
561 InetAddress nextIp;
562 InetAddress relayIp;
563 byte[] clientMac;
Stan Chesnutt045b1662011-02-02 12:10:21 -0800564 List<InetAddress> dnsServers = new ArrayList<InetAddress>();
Stan Chesnutt7da02ad2010-12-14 09:49:26 -0800565 InetAddress gateway = null; // aka router
566 Integer leaseTime = null;
567 InetAddress serverIdentifier = null;
568 InetAddress netMask = null;
569 String message = null;
570 String vendorId = null;
571 byte[] expectedParams = null;
572 String hostName = null;
573 String domainName = null;
574 InetAddress ipSrc = null;
575 InetAddress ipDst = null;
576 InetAddress bcAddr = null;
577 InetAddress requestedIp = null;
578
579 // dhcp options
580 byte dhcpType = (byte) 0xFF;
581
582 packet.order(ByteOrder.BIG_ENDIAN);
583
584 // check to see if we need to parse L2, IP, and UDP encaps
585 if (pktType == ENCAP_L2) {
586 // System.out.println("buffer len " + packet.limit());
587 byte[] l2dst = new byte[6];
588 byte[] l2src = new byte[6];
589
590 packet.get(l2dst);
591 packet.get(l2src);
592
593 short l2type = packet.getShort();
594
595 if (l2type != 0x0800)
596 return null;
597 }
598
599 if ((pktType == ENCAP_L2) || (pktType == ENCAP_L3)) {
600 // assume l2type is 0x0800, i.e. IP
601 byte ipType = packet.get();
602 // System.out.println("ipType is " + ipType);
603 byte ipDiffServicesField = packet.get();
604 short ipTotalLength = packet.getShort();
605 short ipIdentification = packet.getShort();
606 byte ipFlags = packet.get();
607 byte ipFragOffset = packet.get();
608 byte ipTTL = packet.get();
609 byte ipProto = packet.get();
610 short ipChksm = packet.getShort();
611
612 ipSrc = readIpAddress(packet);
613 ipDst = readIpAddress(packet);
614
615 if (ipProto != IP_TYPE_UDP) // UDP
616 return null;
617
618 // assume UDP
619 short udpSrcPort = packet.getShort();
620 short udpDstPort = packet.getShort();
621 short udpLen = packet.getShort();
622 short udpChkSum = packet.getShort();
623
624 if ((udpSrcPort != DHCP_SERVER) && (udpSrcPort != DHCP_CLIENT))
625 return null;
626 }
627
628 // assume bootp
629 byte type = packet.get();
630 byte hwType = packet.get();
631 byte addrLen = packet.get();
632 byte hops = packet.get();
633 transactionId = packet.getInt();
634 short elapsed = packet.getShort();
635 short bootpFlags = packet.getShort();
636 boolean broadcast = (bootpFlags & 0x8000) != 0;
637 byte[] ipv4addr = new byte[4];
638
639 try {
640 packet.get(ipv4addr);
641 clientIp = InetAddress.getByAddress(ipv4addr);
642 packet.get(ipv4addr);
643 yourIp = InetAddress.getByAddress(ipv4addr);
644 packet.get(ipv4addr);
645 nextIp = InetAddress.getByAddress(ipv4addr);
646 packet.get(ipv4addr);
647 relayIp = InetAddress.getByAddress(ipv4addr);
648 } catch (UnknownHostException ex) {
649 return null;
650 }
651
652 clientMac = new byte[addrLen];
653 packet.get(clientMac);
654
655 // skip over address padding (16 octets allocated)
656 packet.position(packet.position() + (16 - addrLen)
657 + 64 // skip server host name (64 chars)
658 + 128); // skip boot file name (128 chars)
659
660 int dhcpMagicCookie = packet.getInt();
661
662 if (dhcpMagicCookie != 0x63825363)
663 return null;
664
665 // parse options
666 boolean notFinishedOptions = true;
667
668 while ((packet.position() < packet.limit()) && notFinishedOptions) {
669 byte optionType = packet.get();
670
671 if (optionType == (byte) 0xFF) {
672 notFinishedOptions = false;
673 } else {
674 byte optionLen = packet.get();
675 int expectedLen = 0;
676
677 switch(optionType) {
678 case DHCP_SUBNET_MASK:
679 netMask = readIpAddress(packet);
680 expectedLen = 4;
681 break;
682 case DHCP_ROUTER:
683 gateway = readIpAddress(packet);
684 expectedLen = 4;
685 break;
686 case DHCP_DNS_SERVER:
Stan Chesnutt7da02ad2010-12-14 09:49:26 -0800687 expectedLen = 0;
688
689 for (expectedLen = 0; expectedLen < optionLen;
690 expectedLen += 4) {
691 dnsServers.add(readIpAddress(packet));
692 }
693 break;
694 case DHCP_HOST_NAME:
695 expectedLen = optionLen;
696 hostName = readAsciiString(packet, optionLen);
697 break;
698 case DHCP_DOMAIN_NAME:
699 expectedLen = optionLen;
700 domainName = readAsciiString(packet, optionLen);
701 break;
702 case DHCP_BROADCAST_ADDRESS:
703 bcAddr = readIpAddress(packet);
704 expectedLen = 4;
705 break;
706 case DHCP_REQUESTED_IP:
707 requestedIp = readIpAddress(packet);
708 expectedLen = 4;
709 break;
710 case DHCP_LEASE_TIME:
711 leaseTime = Integer.valueOf(packet.getInt());
712 expectedLen = 4;
713 break;
714 case DHCP_MESSAGE_TYPE:
715 dhcpType = packet.get();
716 expectedLen = 1;
717 break;
718 case DHCP_SERVER_IDENTIFIER:
719 serverIdentifier = readIpAddress(packet);
720 expectedLen = 4;
721 break;
722 case DHCP_PARAMETER_LIST:
723 expectedParams = new byte[optionLen];
724 packet.get(expectedParams);
725 expectedLen = optionLen;
726 break;
727 case DHCP_MESSAGE:
728 expectedLen = optionLen;
729 message = readAsciiString(packet, optionLen);
730 break;
731 case DHCP_VENDOR_CLASS_ID:
732 expectedLen = optionLen;
733 vendorId = readAsciiString(packet, optionLen);
734 break;
735 case DHCP_CLIENT_IDENTIFIER: { // Client identifier
736 byte[] id = new byte[optionLen];
737 packet.get(id);
738 expectedLen = optionLen;
739 } break;
740 default:
741 // ignore any other parameters
742 for (int i = 0; i < optionLen; i++) {
743 expectedLen++;
744 byte throwaway = packet.get();
745 }
746 }
747
748 if (expectedLen != optionLen) {
749 return null;
750 }
751 }
752 }
753
754 DhcpPacket newPacket;
755
756 switch(dhcpType) {
757 case -1: return null;
758 case DHCP_MESSAGE_TYPE_DISCOVER:
759 newPacket = new DhcpDiscoverPacket(
760 transactionId, clientMac, broadcast);
761 break;
762 case DHCP_MESSAGE_TYPE_OFFER:
763 newPacket = new DhcpOfferPacket(
764 transactionId, broadcast, ipSrc, yourIp, clientMac);
765 break;
766 case DHCP_MESSAGE_TYPE_REQUEST:
767 newPacket = new DhcpRequestPacket(
768 transactionId, clientIp, clientMac, broadcast);
769 break;
770 case DHCP_MESSAGE_TYPE_DECLINE:
771 newPacket = new DhcpDeclinePacket(
772 transactionId, clientIp, yourIp, nextIp, relayIp,
773 clientMac);
774 break;
775 case DHCP_MESSAGE_TYPE_ACK:
776 newPacket = new DhcpAckPacket(
777 transactionId, broadcast, ipSrc, yourIp, clientMac);
778 break;
779 case DHCP_MESSAGE_TYPE_NAK:
780 newPacket = new DhcpNakPacket(
781 transactionId, clientIp, yourIp, nextIp, relayIp,
782 clientMac);
783 break;
784 case DHCP_MESSAGE_TYPE_INFORM:
785 newPacket = new DhcpInformPacket(
786 transactionId, clientIp, yourIp, nextIp, relayIp,
787 clientMac);
788 break;
789 default:
790 System.out.println("Unimplemented type: " + dhcpType);
791 return null;
792 }
793
794 newPacket.mBroadcastAddress = bcAddr;
795 newPacket.mDnsServers = dnsServers;
796 newPacket.mDomainName = domainName;
797 newPacket.mGateway = gateway;
798 newPacket.mHostName = hostName;
799 newPacket.mLeaseTime = leaseTime;
800 newPacket.mMessage = message;
801 newPacket.mRequestedIp = requestedIp;
802 newPacket.mRequestedParams = expectedParams;
803 newPacket.mServerIdentifier = serverIdentifier;
804 newPacket.mSubnetMask = netMask;
805 return newPacket;
806 }
807
808 /**
809 * Parse a packet from an array of bytes.
810 */
811 public static DhcpPacket decodeFullPacket(byte[] packet, int pktType)
812 {
813 ByteBuffer buffer = ByteBuffer.wrap(packet).order(ByteOrder.BIG_ENDIAN);
814 return decodeFullPacket(buffer, pktType);
815 }
816
817 /**
818 * Builds a DHCP-DISCOVER packet from the required specified
819 * parameters.
820 */
821 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
822 byte[] clientMac, boolean broadcast, byte[] expectedParams) {
823 DhcpPacket pkt = new DhcpDiscoverPacket(
824 transactionId, clientMac, broadcast);
825 pkt.mRequestedParams = expectedParams;
826 return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
827 }
828
829 /**
830 * Builds a DHCP-OFFER packet from the required specified
831 * parameters.
832 */
833 public static ByteBuffer buildOfferPacket(int encap, int transactionId,
834 boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr,
835 byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr,
836 InetAddress gateway, List<InetAddress> dnsServers,
837 InetAddress dhcpServerIdentifier, String domainName) {
838 DhcpPacket pkt = new DhcpOfferPacket(
839 transactionId, broadcast, serverIpAddr, clientIpAddr, mac);
840 pkt.mGateway = gateway;
841 pkt.mDnsServers = dnsServers;
842 pkt.mLeaseTime = timeout;
843 pkt.mDomainName = domainName;
844 pkt.mServerIdentifier = dhcpServerIdentifier;
845 pkt.mSubnetMask = netMask;
846 pkt.mBroadcastAddress = bcAddr;
847 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
848 }
849
850 /**
851 * Builds a DHCP-ACK packet from the required specified parameters.
852 */
853 public static ByteBuffer buildAckPacket(int encap, int transactionId,
854 boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr,
855 byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr,
856 InetAddress gateway, List<InetAddress> dnsServers,
857 InetAddress dhcpServerIdentifier, String domainName) {
858 DhcpPacket pkt = new DhcpAckPacket(
859 transactionId, broadcast, serverIpAddr, clientIpAddr, mac);
860 pkt.mGateway = gateway;
861 pkt.mDnsServers = dnsServers;
862 pkt.mLeaseTime = timeout;
863 pkt.mDomainName = domainName;
864 pkt.mSubnetMask = netMask;
865 pkt.mServerIdentifier = dhcpServerIdentifier;
866 pkt.mBroadcastAddress = bcAddr;
867 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
868 }
869
870 /**
871 * Builds a DHCP-NAK packet from the required specified parameters.
872 */
873 public static ByteBuffer buildNakPacket(int encap, int transactionId,
874 InetAddress serverIpAddr, InetAddress clientIpAddr, byte[] mac) {
875 DhcpPacket pkt = new DhcpNakPacket(transactionId, clientIpAddr,
876 serverIpAddr, serverIpAddr, serverIpAddr, mac);
877 pkt.mMessage = "requested address not available";
878 pkt.mRequestedIp = clientIpAddr;
879 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
880 }
881
882 /**
883 * Builds a DHCP-REQUEST packet from the required specified parameters.
884 */
885 public static ByteBuffer buildRequestPacket(int encap,
886 int transactionId, InetAddress clientIp, boolean broadcast,
887 byte[] clientMac, InetAddress requestedIpAddress,
888 InetAddress serverIdentifier, byte[] requestedParams, String hostName) {
889 DhcpPacket pkt = new DhcpRequestPacket(transactionId, clientIp,
890 clientMac, broadcast);
891 pkt.mRequestedIp = requestedIpAddress;
892 pkt.mServerIdentifier = serverIdentifier;
893 pkt.mHostName = hostName;
894 pkt.mRequestedParams = requestedParams;
895 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
896 return result;
897 }
898}