17da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttpackage android.net.dhcp;
27da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
37da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.net.InetAddress;
47da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.net.UnknownHostException;
57da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.nio.ByteBuffer;
67da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.nio.ByteOrder;
7d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughesimport java.nio.charset.StandardCharsets;
87da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.nio.ShortBuffer;
97da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.util.ArrayList;
117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.util.List;
127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt/**
147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt * Defines basic data and operations needed to build and use packets for the
157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt * DHCP protocol.  Subclasses create the specific packets used at each
167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt * stage of the negotiation.
177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt */
187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttabstract class DhcpPacket {
197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final String TAG = "DhcpPacket";
207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Packet encapsulations.
237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static final int ENCAP_L2 = 0;    // EthernetII header included
257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static final int ENCAP_L3 = 1;    // IP/UDP header included
267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static final int ENCAP_BOOTP = 2; // BOOTP contents only
277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP layer definitions.
307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final byte IP_TYPE_UDP = (byte) 0x11;
327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP: Version 4, Header Length 20 bytes
357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP: Flags 0, Fragment Offset 0, Don't Fragment
407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final short IP_FLAGS_OFFSET = (short) 0x4000;
427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP: TOS
457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP: TTL -- use default 64 from RFC1340
507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final byte IP_TTL = (byte) 0x40;
527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The client DHCP port.
557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    static final short DHCP_CLIENT = (short) 68;
577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The server DHCP port.
607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    static final short DHCP_SERVER = (short) 67;
627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The message op code indicating a request from a client.
657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_BOOTREQUEST = (byte) 1;
677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The message op code indicating a response from the server.
707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_BOOTREPLY = (byte) 2;
727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The code type used to identify an Ethernet MAC address in the
757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Client-ID field.
767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte CLIENT_ID_ETHER = (byte) 1;
787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The maximum length of a packet that can be constructed.
817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final int MAX_LENGTH = 1500;
837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Subnet Mask
867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_SUBNET_MASK = 1;
887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected InetAddress mSubnetMask;
897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Router
927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_ROUTER = 3;
947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected InetAddress mGateway;
957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP DNS Server
987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_DNS_SERVER = 6;
1007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected List<InetAddress> mDnsServers;
1017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Host Name
1047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_HOST_NAME = 12;
1067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected String mHostName;
1077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP DOMAIN NAME
1107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_DOMAIN_NAME = 15;
1127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected String mDomainName;
1137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP BROADCAST ADDRESS
1167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_BROADCAST_ADDRESS = 28;
1187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected InetAddress mBroadcastAddress;
1197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Requested IP Address
1227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_REQUESTED_IP = 50;
1247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected InetAddress mRequestedIp;
1257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Lease Time
1287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_LEASE_TIME = 51;
1307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected Integer mLeaseTime;
1317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Message Type
1347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE = 53;
1367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    // the actual type values
1377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
1387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
1397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
1407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
1417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
1427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
1437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
1447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Server Identifier
1477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_SERVER_IDENTIFIER = 54;
1497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected InetAddress mServerIdentifier;
1507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Parameter List
1537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_PARAMETER_LIST = 55;
1557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected byte[] mRequestedParams;
1567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP MESSAGE
1597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE = 56;
1617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected String mMessage;
1627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Renewal Time Value
1657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_RENEWAL_TIME = 58;
1677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: Vendor Class Identifier
1707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_VENDOR_CLASS_ID = 60;
1727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Client Identifier
1757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
1777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The transaction identifier used in this particular DHCP negotiation
1807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected final int mTransId;
1827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The IP address of the client host.  This address is typically
1857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * proposed by the client (from an earlier DHCP negotiation) or
1867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * supplied by the server.
1877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected final InetAddress mClientIp;
1897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected final InetAddress mYourIp;
1907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private final InetAddress mNextIp;
1917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private final InetAddress mRelayIp;
1927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Does the client request a broadcast response?
1957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected boolean mBroadcast;
1977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The six-octet MAC of the client.
2007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected final byte[] mClientMac;
2027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Asks the packet object to signal the next operation in the DHCP
2057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * protocol.  The available actions are methods defined in the
2067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DhcpStateMachine interface.
2077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public abstract void doNextOp(DhcpStateMachine stateMachine);
2097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Asks the packet object to create a ByteBuffer serialization of
2127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * the packet for transmission.
2137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public abstract ByteBuffer buildPacket(int encap, short destUdp,
2157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        short srcUdp);
2167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Allows the concrete class to fill in packet-type-specific details,
2197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * typically optional parameters at the end of the packet.
2207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    abstract void finishPacket(ByteBuffer buffer);
2227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected DhcpPacket(int transId, InetAddress clientIp, InetAddress yourIp,
2247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                         InetAddress nextIp, InetAddress relayIp,
2257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                         byte[] clientMac, boolean broadcast) {
2267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mTransId = transId;
2277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mClientIp = clientIp;
2287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mYourIp = yourIp;
2297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mNextIp = nextIp;
2307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mRelayIp = relayIp;
2317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mClientMac = clientMac;
2327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mBroadcast = broadcast;
2337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
2347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Returns the transaction ID.
2377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public int getTransactionId() {
2397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return mTransId;
2407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
2417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Creates a new L3 packet (including IP header) containing the
2447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP udp packet.  This method relies upon the delegated method
2457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * finishPacket() to insert the per-packet contents.
2467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected void fillInPacket(int encap, InetAddress destIp,
2487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress srcIp, short destUdp, short srcUdp, ByteBuffer buf,
2497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte requestCode, boolean broadcast) {
2507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] destIpArray = destIp.getAddress();
2517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] srcIpArray = srcIp.getAddress();
2527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int ipLengthOffset = 0;
2537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int ipChecksumOffset = 0;
2547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int endIpHeader = 0;
2557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int udpHeaderOffset = 0;
2567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int udpLengthOffset = 0;
2577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int udpChecksumOffset = 0;
2587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.clear();
2607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.order(ByteOrder.BIG_ENDIAN);
2617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // if a full IP packet needs to be generated, put the IP & UDP
2637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // headers in place, and pre-populate with artificial values
2647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // needed to seed the IP checksum.
2657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (encap == ENCAP_L3) {
2667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fake IP header, used in the IP-header checksum
2677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(IP_VERSION_HEADER_LEN);
2687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(IP_TOS_LOWDELAY);    // tos: IPTOS_LOWDELAY
2697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            ipLengthOffset = buf.position();
2707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short)0);  // length
2717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short)0);  // id
2727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment
2737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(IP_TTL);    // TTL: use default 64 from RFC1340
2747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(IP_TYPE_UDP);
2757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            ipChecksumOffset = buf.position();
2767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0); // checksum
2777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(srcIpArray);
2797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(destIpArray);
2807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            endIpHeader = buf.position();
2817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // UDP header
2837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpHeaderOffset = buf.position();
2847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(srcUdp);
2857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(destUdp);
2867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpLengthOffset = buf.position();
2877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0); // length
2887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpChecksumOffset = buf.position();
2897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0); // UDP checksum -- initially zero
2907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
2917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // DHCP payload
2937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(requestCode);
2947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) 1); // Hardware Type: Ethernet
2957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) mClientMac.length); // Hardware Address Length
2967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) 0); // Hop Count
2977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.putInt(mTransId);  // Transaction ID
2987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.putShort((short) 0); // Elapsed Seconds
2997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (broadcast) {
3017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0x8000); // Flags
3027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        } else {
3037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0x0000); // Flags
3047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
3057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mClientIp.getAddress());
3077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mYourIp.getAddress());
3087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mNextIp.getAddress());
3097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mRelayIp.getAddress());
3107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mClientMac);
3117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.position(buf.position() +
3127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                     (16 - mClientMac.length) // pad addr to 16 bytes
3137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                     + 64     // empty server host name (64 bytes)
3147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                     + 128);  // empty boot file name (128 bytes)
3157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.putInt(0x63825363); // magic number
3167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        finishPacket(buf);
3177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // round up to an even number of octets
3197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if ((buf.position() & 1) == 1) {
3207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put((byte) 0);
3217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
3227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // If an IP packet is being built, the IP & UDP checksums must be
3247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // computed.
3257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (encap == ENCAP_L3) {
3267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fix UDP header: insert length
3277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpLen = (short)(buf.position() - udpHeaderOffset);
3287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(udpLengthOffset, udpLen);
3297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fix UDP header: checksum
3307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // checksum for UDP at udpChecksumOffset
3317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            int udpSeed = 0;
3327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // apply IPv4 pseudo-header.  Read IP address src and destination
3347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // values from the IP header and accumulate checksum.
3357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2));
3367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4));
3377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6));
3387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8));
3397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // accumulate extra data for the pseudo-header
3417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += IP_TYPE_UDP;
3427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += udpLen;
3437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // and compute UDP checksum
3447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed,
3457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                                                             udpHeaderOffset,
3467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                                                             buf.position()));
3477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fix IP header: insert length
3487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(ipLengthOffset, (short)buf.position());
3497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fixup IP-header checksum
3507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(ipChecksumOffset,
3517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                         (short) checksum(buf, 0, 0, endIpHeader));
3527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
3537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
3547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
3567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Converts a signed short value to an unsigned int value.  Needed
3577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * because Java does not have unsigned types.
3587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
3597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private int intAbs(short v) {
3607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (v < 0) {
3617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            int r = v + 65536;
3627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            return r;
3637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        } else {
3647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            return(v);
3657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
3667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
3677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
3697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Performs an IP checksum (used in IP header and across UDP
3707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * payload) on the specified portion of a ByteBuffer.  The seed
3717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * allows the checksum to commence with a specified value.
3727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
3737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private int checksum(ByteBuffer buf, int seed, int start, int end) {
3747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int sum = seed;
3757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int bufPosition = buf.position();
3767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // set position of original ByteBuffer, so that the ShortBuffer
3787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // will be correctly initialized
3797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.position(start);
3807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        ShortBuffer shortBuf = buf.asShortBuffer();
3817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // re-set ByteBuffer position
3837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.position(bufPosition);
3847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        short[] shortArray = new short[(end - start) / 2];
3867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        shortBuf.get(shortArray);
3877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        for (short s : shortArray) {
3897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            sum += intAbs(s);
3907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
3917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        start += shortArray.length * 2;
3937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // see if a singleton byte remains
3957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (end != start) {
3967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short b = buf.get(start);
3977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // make it unsigned
3997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            if (b < 0) {
4007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                b += 256;
4017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            }
4027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            sum += b * 256;
4047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF);
4077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF);
4087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int negated = ~sum;
4097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return intAbs((short) negated);
4107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing a single byte value.
4147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected void addTlv(ByteBuffer buf, byte type, byte value) {
4167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(type);
4177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) 1);
4187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(value);
4197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing an array of bytes.
4237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected void addTlv(ByteBuffer buf, byte type, byte[] payload) {
4257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (payload != null) {
4267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(type);
4277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put((byte) payload.length);
4287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(payload);
4297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing an IP address.
4347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected void addTlv(ByteBuffer buf, byte type, InetAddress addr) {
4367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (addr != null) {
4377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            addTlv(buf, type, addr.getAddress());
4387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing a list of IP addresses.
4437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected void addTlv(ByteBuffer buf, byte type, List<InetAddress> addrs) {
4457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (addrs != null && addrs.size() > 0) {
4467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(type);
4477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put((byte)(4 * addrs.size()));
4487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            for (InetAddress addr : addrs) {
4507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                buf.put(addr.getAddress());
4517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            }
4527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing a simple integer
4577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected void addTlv(ByteBuffer buf, byte type, Integer value) {
4597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (value != null) {
4607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(type);
4617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put((byte) 4);
4627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putInt(value.intValue());
4637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing and ASCII string.
4687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected void addTlv(ByteBuffer buf, byte type, String str) {
4707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (str != null) {
4717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(type);
4727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put((byte) str.length());
4737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            for (int i = 0; i < str.length(); i++) {
4757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                buf.put((byte) str.charAt(i));
4767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            }
4777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds the special end-of-optional-parameters indicator.
4827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected void addTlvEnd(ByteBuffer buf) {
4847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) 0xFF);
4857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Converts a MAC from an array of octets to an ASCII string.
4897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static String macToString(byte[] mac) {
4917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String macAddr = "";
4927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        for (int i = 0; i < mac.length; i++) {
4947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            String hexString = "0" + Integer.toHexString(mac[i]);
4957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // substring operation grabs the last 2 digits: this
4977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // allows signed bytes to be converted correctly.
4987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            macAddr += hexString.substring(hexString.length() - 2);
4997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            if (i != (mac.length - 1)) {
5017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                macAddr += ":";
5027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            }
5037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return macAddr;
5067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public String toString() {
5097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String macAddr = macToString(mClientMac);
5107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return macAddr;
5127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
5157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Reads a four-octet value from a ByteBuffer and construct
5167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * an IPv4 address from that value.
5177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
5187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static InetAddress readIpAddress(ByteBuffer packet) {
5197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress result = null;
5207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] ipAddr = new byte[4];
5217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        packet.get(ipAddr);
5227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        try {
5247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            result = InetAddress.getByAddress(ipAddr);
5257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        } catch (UnknownHostException ex) {
5267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // ipAddr is numeric, so this should not be
5277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // triggered.  However, if it is, just nullify
5287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            result = null;
5297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return result;
5327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
5357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Reads a string of specified length from the buffer.
5367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
5377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static String readAsciiString(ByteBuffer buf, int byteCount) {
5387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] bytes = new byte[byteCount];
5397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.get(bytes);
540d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes        return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
5417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
5447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
5457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * buffer may have an L2 encapsulation (which is the full EthernetII
5467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * format starting with the source-address MAC) or an L3 encapsulation
5477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * (which starts with the IP header).
5487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * <br>
5497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * A subset of the optional parameters are parsed and are stored
5507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * in object fields.
5517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
5527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType)
5537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    {
5547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // bootp parameters
5557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int transactionId;
5567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress clientIp;
5577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress yourIp;
5587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress nextIp;
5597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress relayIp;
5607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] clientMac;
561045b166ac27c3b7a67993b029f03088042bf4d5aStan Chesnutt        List<InetAddress> dnsServers = new ArrayList<InetAddress>();
5627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress gateway = null; // aka router
5637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        Integer leaseTime = null;
5647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress serverIdentifier = null;
5657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress netMask = null;
5667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String message = null;
5677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String vendorId = null;
5687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] expectedParams = null;
5697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String hostName = null;
5707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String domainName = null;
5717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress ipSrc = null;
5727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress ipDst = null;
5737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress bcAddr = null;
5747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress requestedIp = null;
5757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // dhcp options
5777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte dhcpType = (byte) 0xFF;
5787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        packet.order(ByteOrder.BIG_ENDIAN);
5807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // check to see if we need to parse L2, IP, and UDP encaps
5827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (pktType == ENCAP_L2) {
5837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // System.out.println("buffer len " + packet.limit());
5847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte[] l2dst = new byte[6];
5857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte[] l2src = new byte[6];
5867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(l2dst);
5887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(l2src);
5897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short l2type = packet.getShort();
5917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            if (l2type != 0x0800)
5937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                return null;
5947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if ((pktType == ENCAP_L2) || (pktType == ENCAP_L3)) {
5977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // assume l2type is 0x0800, i.e. IP
5987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipType = packet.get();
5997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // System.out.println("ipType is " + ipType);
6007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipDiffServicesField = packet.get();
6017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short ipTotalLength = packet.getShort();
6027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short ipIdentification = packet.getShort();
6037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipFlags = packet.get();
6047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipFragOffset = packet.get();
6057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipTTL = packet.get();
6067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipProto = packet.get();
6077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short ipChksm = packet.getShort();
6087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            ipSrc = readIpAddress(packet);
6107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            ipDst = readIpAddress(packet);
6117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            if (ipProto != IP_TYPE_UDP) // UDP
6137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                return null;
6147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // assume UDP
6167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpSrcPort = packet.getShort();
6177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpDstPort = packet.getShort();
6187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpLen = packet.getShort();
6197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpChkSum = packet.getShort();
6207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            if ((udpSrcPort != DHCP_SERVER) && (udpSrcPort != DHCP_CLIENT))
6227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                return null;
6237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
6247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // assume bootp
6267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte type = packet.get();
6277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte hwType = packet.get();
6287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte addrLen = packet.get();
6297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte hops = packet.get();
6307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        transactionId = packet.getInt();
6317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        short elapsed = packet.getShort();
6327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        short bootpFlags = packet.getShort();
6337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        boolean broadcast = (bootpFlags & 0x8000) != 0;
6347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] ipv4addr = new byte[4];
6357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        try {
6377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(ipv4addr);
6387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            clientIp = InetAddress.getByAddress(ipv4addr);
6397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(ipv4addr);
6407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            yourIp = InetAddress.getByAddress(ipv4addr);
6417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(ipv4addr);
6427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            nextIp = InetAddress.getByAddress(ipv4addr);
6437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(ipv4addr);
6447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            relayIp = InetAddress.getByAddress(ipv4addr);
6457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        } catch (UnknownHostException ex) {
6467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            return null;
6477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
6487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        clientMac = new byte[addrLen];
6507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        packet.get(clientMac);
6517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // skip over address padding (16 octets allocated)
6537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        packet.position(packet.position() + (16 - addrLen)
6547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        + 64    // skip server host name (64 chars)
6557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        + 128); // skip boot file name (128 chars)
6567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int dhcpMagicCookie = packet.getInt();
6587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (dhcpMagicCookie !=  0x63825363)
6607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            return null;
6617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // parse options
6637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        boolean notFinishedOptions = true;
6647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        while ((packet.position() < packet.limit()) && notFinishedOptions) {
6667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte optionType = packet.get();
6677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            if (optionType == (byte) 0xFF) {
6697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                notFinishedOptions = false;
6707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            } else {
6717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                byte optionLen = packet.get();
6727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                int expectedLen = 0;
6737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                switch(optionType) {
6757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_SUBNET_MASK:
6767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        netMask = readIpAddress(packet);
6777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = 4;
6787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
6797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_ROUTER:
6807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        gateway = readIpAddress(packet);
6817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = 4;
6827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
6837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_DNS_SERVER:
6847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = 0;
6857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        for (expectedLen = 0; expectedLen < optionLen;
6877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                             expectedLen += 4) {
6887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                            dnsServers.add(readIpAddress(packet));
6897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        }
6907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
6917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_HOST_NAME:
6927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = optionLen;
6937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        hostName = readAsciiString(packet, optionLen);
6947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
6957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_DOMAIN_NAME:
6967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = optionLen;
6977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        domainName = readAsciiString(packet, optionLen);
6987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
6997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_BROADCAST_ADDRESS:
7007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        bcAddr = readIpAddress(packet);
7017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = 4;
7027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
7037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_REQUESTED_IP:
7047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        requestedIp = readIpAddress(packet);
7057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = 4;
7067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
7077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_LEASE_TIME:
7087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        leaseTime = Integer.valueOf(packet.getInt());
7097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = 4;
7107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
7117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_MESSAGE_TYPE:
7127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        dhcpType = packet.get();
7137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = 1;
7147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
7157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_SERVER_IDENTIFIER:
7167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        serverIdentifier = readIpAddress(packet);
7177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = 4;
7187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
7197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_PARAMETER_LIST:
7207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedParams = new byte[optionLen];
7217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        packet.get(expectedParams);
7227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = optionLen;
7237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
7247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_MESSAGE:
7257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = optionLen;
7267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        message = readAsciiString(packet, optionLen);
7277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
7287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_VENDOR_CLASS_ID:
7297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = optionLen;
7307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        vendorId = readAsciiString(packet, optionLen);
7317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        break;
7327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    case DHCP_CLIENT_IDENTIFIER: { // Client identifier
7337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        byte[] id = new byte[optionLen];
7347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        packet.get(id);
7357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        expectedLen = optionLen;
7367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    } break;
7377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    default:
7387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        // ignore any other parameters
7397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        for (int i = 0; i < optionLen; i++) {
7407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                            expectedLen++;
7417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                            byte throwaway = packet.get();
7427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        }
7437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                }
7447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                if (expectedLen != optionLen) {
7467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    return null;
7477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                }
7487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            }
7497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
7507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket newPacket;
7527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        switch(dhcpType) {
7547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case -1: return null;
7557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_DISCOVER:
7567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpDiscoverPacket(
7577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    transactionId, clientMac, broadcast);
7587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
7597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_OFFER:
7607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpOfferPacket(
7617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    transactionId, broadcast, ipSrc, yourIp, clientMac);
7627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
7637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_REQUEST:
7647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpRequestPacket(
7657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    transactionId, clientIp, clientMac, broadcast);
7667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
7677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_DECLINE:
7687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpDeclinePacket(
7697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    transactionId, clientIp, yourIp, nextIp, relayIp,
7707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    clientMac);
7717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
7727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_ACK:
7737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpAckPacket(
7747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    transactionId, broadcast, ipSrc, yourIp, clientMac);
7757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
7767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_NAK:
7777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpNakPacket(
7787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    transactionId, clientIp, yourIp, nextIp, relayIp,
7797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    clientMac);
7807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
7817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_INFORM:
7827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpInformPacket(
7837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    transactionId, clientIp, yourIp, nextIp, relayIp,
7847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    clientMac);
7857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
7867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            default:
7877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                System.out.println("Unimplemented type: " + dhcpType);
7887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                return null;
7897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
7907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mBroadcastAddress = bcAddr;
7927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mDnsServers = dnsServers;
7937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mDomainName = domainName;
7947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mGateway = gateway;
7957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mHostName = hostName;
7967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mLeaseTime = leaseTime;
7977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mMessage = message;
7987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mRequestedIp = requestedIp;
7997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mRequestedParams = expectedParams;
8007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mServerIdentifier = serverIdentifier;
8017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mSubnetMask = netMask;
8027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return newPacket;
8037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
8047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
8067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Parse a packet from an array of bytes.
8077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
8087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static DhcpPacket decodeFullPacket(byte[] packet, int pktType)
8097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    {
8107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        ByteBuffer buffer = ByteBuffer.wrap(packet).order(ByteOrder.BIG_ENDIAN);
8117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return decodeFullPacket(buffer, pktType);
8127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
8137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
8157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-DISCOVER packet from the required specified
8167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * parameters.
8177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
8187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
8197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] clientMac, boolean broadcast, byte[] expectedParams) {
8207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket pkt = new DhcpDiscoverPacket(
8217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            transactionId, clientMac, broadcast);
8227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mRequestedParams = expectedParams;
8237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
8247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
8257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
8277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-OFFER packet from the required specified
8287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * parameters.
8297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
8307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildOfferPacket(int encap, int transactionId,
8317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr,
8327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr,
8337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress gateway, List<InetAddress> dnsServers,
8347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress dhcpServerIdentifier, String domainName) {
8357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket pkt = new DhcpOfferPacket(
8367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            transactionId, broadcast, serverIpAddr, clientIpAddr, mac);
8377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mGateway = gateway;
8387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mDnsServers = dnsServers;
8397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mLeaseTime = timeout;
8407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mDomainName = domainName;
8417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mServerIdentifier = dhcpServerIdentifier;
8427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mSubnetMask = netMask;
8437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mBroadcastAddress = bcAddr;
8447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
8457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
8467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
8487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-ACK packet from the required specified parameters.
8497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
8507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildAckPacket(int encap, int transactionId,
8517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr,
8527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr,
8537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress gateway, List<InetAddress> dnsServers,
8547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress dhcpServerIdentifier, String domainName) {
8557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket pkt = new DhcpAckPacket(
8567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            transactionId, broadcast, serverIpAddr, clientIpAddr, mac);
8577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mGateway = gateway;
8587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mDnsServers = dnsServers;
8597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mLeaseTime = timeout;
8607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mDomainName = domainName;
8617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mSubnetMask = netMask;
8627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mServerIdentifier = dhcpServerIdentifier;
8637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mBroadcastAddress = bcAddr;
8647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
8657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
8667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
8687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-NAK packet from the required specified parameters.
8697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
8707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildNakPacket(int encap, int transactionId,
8717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress serverIpAddr, InetAddress clientIpAddr, byte[] mac) {
8727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket pkt = new DhcpNakPacket(transactionId, clientIpAddr,
8737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            serverIpAddr, serverIpAddr, serverIpAddr, mac);
8747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mMessage = "requested address not available";
8757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mRequestedIp = clientIpAddr;
8767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
8777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
8787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
8807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-REQUEST packet from the required specified parameters.
8817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
8827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildRequestPacket(int encap,
8837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int transactionId, InetAddress clientIp, boolean broadcast,
8847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] clientMac, InetAddress requestedIpAddress,
8857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        InetAddress serverIdentifier, byte[] requestedParams, String hostName) {
8867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket pkt = new DhcpRequestPacket(transactionId, clientIp,
8877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            clientMac, broadcast);
8887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mRequestedIp = requestedIpAddress;
8897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mServerIdentifier = serverIdentifier;
8907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mHostName = hostName;
8917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mRequestedParams = requestedParams;
8927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
8937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return result;
8947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
8957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt}
896