17da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttpackage android.net.dhcp;
27da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
386bff86778d006d59a36bb10c7a577d982934402Lorenzo Colittiimport android.net.DhcpResults;
486bff86778d006d59a36bb10c7a577d982934402Lorenzo Colittiimport android.net.LinkAddress;
586bff86778d006d59a36bb10c7a577d982934402Lorenzo Colittiimport android.net.NetworkUtils;
66241874355c0e0d9ff04e993ad1d522c66b8c50bHugo Benichiimport android.net.metrics.DhcpErrorEvent;
786bff86778d006d59a36bb10c7a577d982934402Lorenzo Colittiimport android.os.Build;
886bff86778d006d59a36bb10c7a577d982934402Lorenzo Colittiimport android.os.SystemProperties;
97f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colittiimport android.system.OsConstants;
10511818ffb3a21de86d02ccc29e3c1c92d75c81c4Erik Klineimport android.text.TextUtils;
11e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichiimport com.android.internal.annotations.VisibleForTesting;
127f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti
1306ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colittiimport java.io.UnsupportedEncodingException;
1451697effe9567a144532190ad534370a00c15996Lorenzo Colittiimport java.net.Inet4Address;
157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.net.UnknownHostException;
16fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colittiimport java.nio.BufferUnderflowException;
177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.nio.ByteBuffer;
187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.nio.ByteOrder;
197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.nio.ShortBuffer;
20e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichiimport java.nio.charset.StandardCharsets;
217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.util.ArrayList;
22eca9b9bd8b9a4d0a2de8af8edc20834dd46b98b3Lorenzo Colittiimport java.util.Arrays;
237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnuttimport java.util.List;
247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt/**
267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt * Defines basic data and operations needed to build and use packets for the
277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt * DHCP protocol.  Subclasses create the specific packets used at each
287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt * stage of the negotiation.
29473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline *
30473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Kline * @hide
317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt */
32473355f96b91a1fbeb6f8f8f0bcd3c887da12f40Erik Klinepublic abstract class DhcpPacket {
337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final String TAG = "DhcpPacket";
347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
35d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti    // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
36d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti    // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the
37d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti    // DHCP client timeout.
38d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti    public static final int MINIMUM_LEASE = 60;
39d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti    public static final int INFINITE_LEASE = (int) 0xffffffff;
40d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti
4151697effe9567a144532190ad534370a00c15996Lorenzo Colitti    public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY;
4251697effe9567a144532190ad534370a00c15996Lorenzo Colitti    public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL;
437f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti    public static final byte[] ETHER_BROADCAST = new byte[] {
447f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            (byte) 0xff, (byte) 0xff, (byte) 0xff,
457f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            (byte) 0xff, (byte) 0xff, (byte) 0xff,
467f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti    };
4751697effe9567a144532190ad534370a00c15996Lorenzo Colitti
487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Packet encapsulations.
507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static final int ENCAP_L2 = 0;    // EthernetII header included
527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static final int ENCAP_L3 = 1;    // IP/UDP header included
537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static final int ENCAP_BOOTP = 2; // BOOTP contents only
547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
56b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti     * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
57b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti     */
58b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti    public static final int MIN_PACKET_LENGTH_BOOTP = 236;  // See diagram in RFC 2131, section 2.
59b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti    public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
60b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti    public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
61b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti
62d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti    public static final int HWADDR_LEN = 16;
6306ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti    public static final int MAX_OPTION_LEN = 255;
6477fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti
6577fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti    /**
6677fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti     * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
6777fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti     * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
6877fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti     * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
6977fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti     * because in general it is risky to assume that the hardware is able to send/receive packets
7077fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti     * larger than 1500 bytes even if the network supports it.
7177fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti     */
7277fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti    private static final int MIN_MTU = 1280;
7377fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti    private static final int MAX_MTU = 1500;
7477fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti
75b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti    /**
767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP layer definitions.
777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final byte IP_TYPE_UDP = (byte) 0x11;
797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP: Version 4, Header Length 20 bytes
827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP: Flags 0, Fragment Offset 0, Don't Fragment
877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final short IP_FLAGS_OFFSET = (short) 0x4000;
897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP: TOS
927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * IP: TTL -- use default 64 from RFC1340
977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private static final byte IP_TTL = (byte) 0x40;
997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The client DHCP port.
1027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    static final short DHCP_CLIENT = (short) 68;
1047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The server DHCP port.
1077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    static final short DHCP_SERVER = (short) 67;
1097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The message op code indicating a request from a client.
1127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_BOOTREQUEST = (byte) 1;
1147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The message op code indicating a response from the server.
1177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_BOOTREPLY = (byte) 2;
1197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The code type used to identify an Ethernet MAC address in the
1227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Client-ID field.
1237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte CLIENT_ID_ETHER = (byte) 1;
1257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The maximum length of a packet that can be constructed.
1287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final int MAX_LENGTH = 1500;
1307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
132496906ee7008b72619f230c65f103533d4d2d68aErik Kline     * The magic cookie that identifies this as a DHCP packet instead of BOOTP.
133496906ee7008b72619f230c65f103533d4d2d68aErik Kline     */
134496906ee7008b72619f230c65f103533d4d2d68aErik Kline    private static final int DHCP_MAGIC_COOKIE = 0x63825363;
135496906ee7008b72619f230c65f103533d4d2d68aErik Kline
136496906ee7008b72619f230c65f103533d4d2d68aErik Kline    /**
1377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Subnet Mask
1387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_SUBNET_MASK = 1;
14051697effe9567a144532190ad534370a00c15996Lorenzo Colitti    protected Inet4Address mSubnetMask;
1417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Router
1447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_ROUTER = 3;
146025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti    protected List <Inet4Address> mGateways;
1477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP DNS Server
1507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_DNS_SERVER = 6;
15251697effe9567a144532190ad534370a00c15996Lorenzo Colitti    protected List<Inet4Address> mDnsServers;
1537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Host Name
1567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_HOST_NAME = 12;
1587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected String mHostName;
1597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP DOMAIN NAME
1627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_DOMAIN_NAME = 15;
1647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected String mDomainName;
1657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
167fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     * DHCP Optional Type: DHCP Interface MTU
168fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     */
169fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static final byte DHCP_MTU = 26;
170fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected Short mMtu;
171fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti
172fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    /**
1737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP BROADCAST ADDRESS
1747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_BROADCAST_ADDRESS = 28;
17651697effe9567a144532190ad534370a00c15996Lorenzo Colitti    protected Inet4Address mBroadcastAddress;
1777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
179b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti     * DHCP Optional Type: Vendor specific information
180b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti     */
181b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti    protected static final byte DHCP_VENDOR_INFO = 43;
182b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti    protected String mVendorInfo;
183b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti
184b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti    /**
1857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Requested IP Address
1867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_REQUESTED_IP = 50;
18851697effe9567a144532190ad534370a00c15996Lorenzo Colitti    protected Inet4Address mRequestedIp;
1897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Lease Time
1927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_LEASE_TIME = 51;
1947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected Integer mLeaseTime;
1957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
1967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
1977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Message Type
1987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
1997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE = 53;
2007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    // the actual type values
2017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
2027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
2037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
2047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
2057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
2067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
2077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
2087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Server Identifier
2117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_SERVER_IDENTIFIER = 54;
21351697effe9567a144532190ad534370a00c15996Lorenzo Colitti    protected Inet4Address mServerIdentifier;
2147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Parameter List
2177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_PARAMETER_LIST = 55;
2197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected byte[] mRequestedParams;
2207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP MESSAGE
2237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_MESSAGE = 56;
2257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected String mMessage;
2267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
228fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     * DHCP Optional Type: Maximum DHCP Message Size
229fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     */
230fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static final byte DHCP_MAX_MESSAGE_SIZE = 57;
231fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected Short mMaxMessageSize;
232fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti
233fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    /**
2347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Renewal Time Value
2357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_RENEWAL_TIME = 58;
237fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected Integer mT1;
238fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti
239fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    /**
240fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     * DHCP Optional Type: Rebinding Time Value
241fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     */
242fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static final byte DHCP_REBINDING_TIME = 59;
243fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected Integer mT2;
2447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: Vendor Class Identifier
2477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_VENDOR_CLASS_ID = 60;
24986bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti    protected String mVendorId;
2507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP Optional Type: DHCP Client Identifier
2537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
2557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
257b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti     * DHCP zero-length option code: pad
258b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti     */
259b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti    protected static final byte DHCP_OPTION_PAD = 0x00;
260b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti
261b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti    /**
262b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti     * DHCP zero-length option code: end of options
263b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti     */
264b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti    protected static final byte DHCP_OPTION_END = (byte) 0xff;
265b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti
266b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti    /**
2677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The transaction identifier used in this particular DHCP negotiation
2687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected final int mTransId;
2707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2723e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti     * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only.
2733e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti     */
2743e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti    protected final short mSecs;
2753e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti
2763e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti    /**
2777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The IP address of the client host.  This address is typically
2787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * proposed by the client (from an earlier DHCP negotiation) or
2797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * supplied by the server.
2807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
28151697effe9567a144532190ad534370a00c15996Lorenzo Colitti    protected final Inet4Address mClientIp;
28251697effe9567a144532190ad534370a00c15996Lorenzo Colitti    protected final Inet4Address mYourIp;
28351697effe9567a144532190ad534370a00c15996Lorenzo Colitti    private final Inet4Address mNextIp;
28451697effe9567a144532190ad534370a00c15996Lorenzo Colitti    private final Inet4Address mRelayIp;
2857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Does the client request a broadcast response?
2887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected boolean mBroadcast;
2907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * The six-octet MAC of the client.
2937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
2947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    protected final byte[] mClientMac;
2957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
2967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
2977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Asks the packet object to create a ByteBuffer serialization of
2987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * the packet for transmission.
2997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
3007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public abstract ByteBuffer buildPacket(int encap, short destUdp,
3017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        short srcUdp);
3027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
3047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Allows the concrete class to fill in packet-type-specific details,
3057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * typically optional parameters at the end of the packet.
3067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
3077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    abstract void finishPacket(ByteBuffer buffer);
3087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3096c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti    // Set in unit tests, to ensure that the test does not break when run on different devices and
3106c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti    // on different releases.
3116c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti    static String testOverrideVendorId = null;
3126c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti    static String testOverrideHostname = null;
3136c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti
3143e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti    protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
31551697effe9567a144532190ad534370a00c15996Lorenzo Colitti                         Inet4Address nextIp, Inet4Address relayIp,
3167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                         byte[] clientMac, boolean broadcast) {
3177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mTransId = transId;
3183e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti        mSecs = secs;
3197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mClientIp = clientIp;
3207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mYourIp = yourIp;
3217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mNextIp = nextIp;
3227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mRelayIp = relayIp;
3237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mClientMac = clientMac;
3247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        mBroadcast = broadcast;
3257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
3267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
3287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Returns the transaction ID.
3297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
3307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public int getTransactionId() {
3317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return mTransId;
3327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
3337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
33586bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti     * Returns the client MAC.
33686bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti     */
33786bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti    public byte[] getClientMac() {
33886bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        return mClientMac;
33986bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti    }
34086bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti
34186bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti    /**
342f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti     * Returns the client ID. This follows RFC 2132 and is based on the hardware address.
343f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti     */
344f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti    public byte[] getClientId() {
345f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti        byte[] clientId = new byte[mClientMac.length + 1];
346f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti        clientId[0] = CLIENT_ID_ETHER;
347f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti        System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length);
348f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti        return clientId;
349f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti    }
350f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti
351f443bfc25e80ef46aedd616d4ecb4c95abd7be7aLorenzo Colitti    /**
3527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Creates a new L3 packet (including IP header) containing the
3537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * DHCP udp packet.  This method relies upon the delegated method
3547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * finishPacket() to insert the per-packet contents.
3557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
35651697effe9567a144532190ad534370a00c15996Lorenzo Colitti    protected void fillInPacket(int encap, Inet4Address destIp,
35751697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf,
3587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte requestCode, boolean broadcast) {
3597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] destIpArray = destIp.getAddress();
3607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] srcIpArray = srcIp.getAddress();
3617f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti        int ipHeaderOffset = 0;
3627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int ipLengthOffset = 0;
3637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int ipChecksumOffset = 0;
3647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int endIpHeader = 0;
3657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int udpHeaderOffset = 0;
3667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int udpLengthOffset = 0;
3677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int udpChecksumOffset = 0;
3687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.clear();
3707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.order(ByteOrder.BIG_ENDIAN);
3717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3727f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti        if (encap == ENCAP_L2) {
3737f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            buf.put(ETHER_BROADCAST);
3747f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            buf.put(mClientMac);
3757f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            buf.putShort((short) OsConstants.ETH_P_IP);
3767f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti        }
3777f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti
3787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // if a full IP packet needs to be generated, put the IP & UDP
3797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // headers in place, and pre-populate with artificial values
3807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // needed to seed the IP checksum.
3817f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti        if (encap <= ENCAP_L3) {
3827f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            ipHeaderOffset = buf.position();
3837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(IP_VERSION_HEADER_LEN);
3847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(IP_TOS_LOWDELAY);    // tos: IPTOS_LOWDELAY
3857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            ipLengthOffset = buf.position();
3867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short)0);  // length
3877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short)0);  // id
3887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment
3897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(IP_TTL);    // TTL: use default 64 from RFC1340
3907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(IP_TYPE_UDP);
3917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            ipChecksumOffset = buf.position();
3927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0); // checksum
3937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(srcIpArray);
3957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(destIpArray);
3967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            endIpHeader = buf.position();
3977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
3987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // UDP header
3997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpHeaderOffset = buf.position();
4007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(srcUdp);
4017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(destUdp);
4027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpLengthOffset = buf.position();
4037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0); // length
4047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpChecksumOffset = buf.position();
4057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0); // UDP checksum -- initially zero
4067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // DHCP payload
4097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(requestCode);
4107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) 1); // Hardware Type: Ethernet
4117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) mClientMac.length); // Hardware Address Length
4127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) 0); // Hop Count
4137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.putInt(mTransId);  // Transaction ID
4143e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti        buf.putShort(mSecs); // Elapsed Seconds
4157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (broadcast) {
4177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0x8000); // Flags
4187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        } else {
4197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort((short) 0x0000); // Flags
4207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mClientIp.getAddress());
4237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mYourIp.getAddress());
4247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mNextIp.getAddress());
4257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mRelayIp.getAddress());
4267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(mClientMac);
4277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.position(buf.position() +
428d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti                     (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
4297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                     + 64     // empty server host name (64 bytes)
4307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                     + 128);  // empty boot file name (128 bytes)
431496906ee7008b72619f230c65f103533d4d2d68aErik Kline        buf.putInt(DHCP_MAGIC_COOKIE); // magic number
4327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        finishPacket(buf);
4337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // round up to an even number of octets
4357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if ((buf.position() & 1) == 1) {
4367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put((byte) 0);
4377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4397da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // If an IP packet is being built, the IP & UDP checksums must be
4407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // computed.
4417f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti        if (encap <= ENCAP_L3) {
4427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fix UDP header: insert length
4437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpLen = (short)(buf.position() - udpHeaderOffset);
4447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(udpLengthOffset, udpLen);
4457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fix UDP header: checksum
4467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // checksum for UDP at udpChecksumOffset
4477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            int udpSeed = 0;
4487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // apply IPv4 pseudo-header.  Read IP address src and destination
4507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // values from the IP header and accumulate checksum.
4517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2));
4527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4));
4537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6));
4547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8));
4557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // accumulate extra data for the pseudo-header
4577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += IP_TYPE_UDP;
4587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            udpSeed += udpLen;
4597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // and compute UDP checksum
4607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed,
4617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                                                             udpHeaderOffset,
4627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                                                             buf.position()));
4637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fix IP header: insert length
4647f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset));
4657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // fixup IP-header checksum
4667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putShort(ipChecksumOffset,
4677f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti                         (short) checksum(buf, 0, ipHeaderOffset, endIpHeader));
4687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
4697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Converts a signed short value to an unsigned int value.  Needed
4737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * because Java does not have unsigned types.
4747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
475b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti    private static int intAbs(short v) {
476b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti        return v & 0xFFFF;
4777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
4787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
4807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Performs an IP checksum (used in IP header and across UDP
4817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * payload) on the specified portion of a ByteBuffer.  The seed
4827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * allows the checksum to commence with a specified value.
4837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
4847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    private int checksum(ByteBuffer buf, int seed, int start, int end) {
4857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int sum = seed;
4867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int bufPosition = buf.position();
4877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // set position of original ByteBuffer, so that the ShortBuffer
4897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // will be correctly initialized
4907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.position(start);
4917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        ShortBuffer shortBuf = buf.asShortBuffer();
4927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // re-set ByteBuffer position
4947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.position(bufPosition);
4957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        short[] shortArray = new short[(end - start) / 2];
4977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        shortBuf.get(shortArray);
4987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
4997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        for (short s : shortArray) {
5007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            sum += intAbs(s);
5017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        start += shortArray.length * 2;
5047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // see if a singleton byte remains
5067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (end != start) {
5077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short b = buf.get(start);
5087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // make it unsigned
5107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            if (b < 0) {
5117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                b += 256;
5127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            }
5137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            sum += b * 256;
5157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF);
5187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF);
5197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int negated = ~sum;
5207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return intAbs((short) negated);
5217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
5247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing a single byte value.
5257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
526fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static void addTlv(ByteBuffer buf, byte type, byte value) {
5277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(type);
5287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) 1);
5297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put(value);
5307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
5337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing an array of bytes.
5347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
535fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static void addTlv(ByteBuffer buf, byte type, byte[] payload) {
5367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (payload != null) {
53706ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti            if (payload.length > MAX_OPTION_LEN) {
53806ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti                throw new IllegalArgumentException("DHCP option too long: "
53906ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti                        + payload.length + " vs. " + MAX_OPTION_LEN);
54006ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti            }
5417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(type);
5427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put((byte) payload.length);
5437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(payload);
5447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
5487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing an IP address.
5497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
550fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static void addTlv(ByteBuffer buf, byte type, Inet4Address addr) {
5517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (addr != null) {
5527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            addTlv(buf, type, addr.getAddress());
5537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
5577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing a list of IP addresses.
5587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
559fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static void addTlv(ByteBuffer buf, byte type, List<Inet4Address> addrs) {
56006ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        if (addrs == null || addrs.size() == 0) return;
5617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
56206ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        int optionLen = 4 * addrs.size();
56306ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        if (optionLen > MAX_OPTION_LEN) {
56406ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti            throw new IllegalArgumentException("DHCP option too long: "
56506ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti                    + optionLen + " vs. " + MAX_OPTION_LEN);
56606ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        }
56706ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti
56806ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        buf.put(type);
56906ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        buf.put((byte)(optionLen));
57006ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti
57106ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        for (Inet4Address addr : addrs) {
57206ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti            buf.put(addr.getAddress());
5737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
577fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     * Adds an optional parameter containing a short integer
578fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     */
579fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static void addTlv(ByteBuffer buf, byte type, Short value) {
580fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        if (value != null) {
581fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti            buf.put(type);
582fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti            buf.put((byte) 2);
583fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti            buf.putShort(value.shortValue());
584fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        }
585fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    }
586fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti
587fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    /**
5887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds an optional parameter containing a simple integer
5897da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
590fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static void addTlv(ByteBuffer buf, byte type, Integer value) {
5917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (value != null) {
5927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put(type);
5937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.put((byte) 4);
5947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            buf.putInt(value.intValue());
5957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
5967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
5977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
5987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
59906ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti     * Adds an optional parameter containing an ASCII string.
6007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
601fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static void addTlv(ByteBuffer buf, byte type, String str) {
60206ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        try {
60306ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti            addTlv(buf, type, str.getBytes("US-ASCII"));
60406ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti        } catch (UnsupportedEncodingException e) {
60506ac4b8dd1877d8a82103f11c236f1527b692f94Lorenzo Colitti           throw new IllegalArgumentException("String is not US-ASCII: " + str);
6067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
6077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
6087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
6107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Adds the special end-of-optional-parameters indicator.
6117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
612fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected static void addTlvEnd(ByteBuffer buf) {
6137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.put((byte) 0xFF);
6147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
6157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6166c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti    private String getVendorId() {
6176c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti        if (testOverrideVendorId != null) return testOverrideVendorId;
6186c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti        return "android-dhcp-" + Build.VERSION.RELEASE;
6196c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti    }
6206c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti
6216c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti    private String getHostname() {
6226c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti        if (testOverrideHostname != null) return testOverrideHostname;
6236c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti        return SystemProperties.get("net.hostname");
6246c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti    }
6256c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti
6267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
627fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     * Adds common client TLVs.
628fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     *
629fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket
630fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     * methods to take them.
631fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti     */
632fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    protected void addCommonClientTlvs(ByteBuffer buf) {
633fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
6346c7acb6ec7494235dd80d972fb3db0f7b48fb4fcLorenzo Colitti        addTlv(buf, DHCP_VENDOR_CLASS_ID, getVendorId());
635511818ffb3a21de86d02ccc29e3c1c92d75c81c4Erik Kline        final String hn = getHostname();
636511818ffb3a21de86d02ccc29e3c1c92d75c81c4Erik Kline        if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn);
637fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    }
638fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti
639fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti    /**
6407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Converts a MAC from an array of octets to an ASCII string.
6417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
6427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static String macToString(byte[] mac) {
6437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String macAddr = "";
6447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        for (int i = 0; i < mac.length; i++) {
6467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            String hexString = "0" + Integer.toHexString(mac[i]);
6477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // substring operation grabs the last 2 digits: this
6497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // allows signed bytes to be converted correctly.
6507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            macAddr += hexString.substring(hexString.length() - 2);
6517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            if (i != (mac.length - 1)) {
6537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                macAddr += ":";
6547da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            }
6557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
6567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return macAddr;
6587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
6597da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public String toString() {
6617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String macAddr = macToString(mClientMac);
6627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return macAddr;
6647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
6657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
6677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Reads a four-octet value from a ByteBuffer and construct
6687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * an IPv4 address from that value.
6697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
67051697effe9567a144532190ad534370a00c15996Lorenzo Colitti    private static Inet4Address readIpAddress(ByteBuffer packet) {
67151697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address result = null;
6727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] ipAddr = new byte[4];
6737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        packet.get(ipAddr);
6747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        try {
67651697effe9567a144532190ad534370a00c15996Lorenzo Colitti            result = (Inet4Address) Inet4Address.getByAddress(ipAddr);
6777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        } catch (UnknownHostException ex) {
6787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // ipAddr is numeric, so this should not be
6797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // triggered.  However, if it is, just nullify
6807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            result = null;
6817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
6827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return result;
6847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
6857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
6867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
6877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Reads a string of specified length from the buffer.
6887da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
689a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti    private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
6907da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] bytes = new byte[byteCount];
6917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        buf.get(bytes);
692a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti        int length = bytes.length;
693a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti        if (!nullOk) {
694a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti            // Stop at the first null byte. This is because some DHCP options (e.g., the domain
695a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti            // name) are passed to netd via FrameworkListener, which refuses arguments containing
696a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti            // null bytes. We don't do this by default because vendorInfo is an opaque string which
697a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti            // could in theory contain null bytes.
698a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti            for (length = 0; length < bytes.length; length++) {
699a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti                if (bytes[length] == 0) {
700a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti                    break;
701a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti                }
702a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti            }
703a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti        }
704a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti        return new String(bytes, 0, length, StandardCharsets.US_ASCII);
7057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
7067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
707b19238c48814c5a1438b1238794e121876ae89abErik Kline    private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
708b19238c48814c5a1438b1238794e121876ae89abErik Kline        return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
709b19238c48814c5a1438b1238794e121876ae89abErik Kline    }
710b19238c48814c5a1438b1238794e121876ae89abErik Kline
711b19238c48814c5a1438b1238794e121876ae89abErik Kline    private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) {
712b19238c48814c5a1438b1238794e121876ae89abErik Kline        return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER);
713b19238c48814c5a1438b1238794e121876ae89abErik Kline    }
714b19238c48814c5a1438b1238794e121876ae89abErik Kline
715496906ee7008b72619f230c65f103533d4d2d68aErik Kline    public static class ParseException extends Exception {
7162677b1957b444e2dae5737feee989109b811547cHugo Benichi        public final int errorCode;
7172677b1957b444e2dae5737feee989109b811547cHugo Benichi        public ParseException(int errorCode, String msg, Object... args) {
718496906ee7008b72619f230c65f103533d4d2d68aErik Kline            super(String.format(msg, args));
7192677b1957b444e2dae5737feee989109b811547cHugo Benichi            this.errorCode = errorCode;
720496906ee7008b72619f230c65f103533d4d2d68aErik Kline        }
721496906ee7008b72619f230c65f103533d4d2d68aErik Kline    }
722496906ee7008b72619f230c65f103533d4d2d68aErik Kline
7237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
7247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
7257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * buffer may have an L2 encapsulation (which is the full EthernetII
7267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * format starting with the source-address MAC) or an L3 encapsulation
7277da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * (which starts with the IP header).
7287da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * <br>
7297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * A subset of the optional parameters are parsed and are stored
7307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * in object fields.
7317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
732e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi    @VisibleForTesting
733e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
7347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    {
7357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // bootp parameters
7367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        int transactionId;
7373e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti        short secs;
73851697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address clientIp;
73951697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address yourIp;
74051697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address nextIp;
74151697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address relayIp;
7427da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] clientMac;
743025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        List<Inet4Address> dnsServers = new ArrayList<>();
744025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        List<Inet4Address> gateways = new ArrayList<>();  // aka router
74551697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address serverIdentifier = null;
74651697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address netMask = null;
7477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String message = null;
7487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String vendorId = null;
749b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti        String vendorInfo = null;
7507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] expectedParams = null;
7517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String hostName = null;
7527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        String domainName = null;
75351697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address ipSrc = null;
75451697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address ipDst = null;
75551697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address bcAddr = null;
75651697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address requestedIp = null;
7577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
758fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        // The following are all unsigned integers. Internally we store them as signed integers of
759fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        // the same length because that way we're guaranteed that they can't be out of the range of
760fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
761fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        // to cast it.
762fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        Short mtu = null;
763fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        Short maxMessageSize = null;
764fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        Integer leaseTime = null;
765fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        Integer T1 = null;
766fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        Integer T2 = null;
767fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti
7687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // dhcp options
7697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte dhcpType = (byte) 0xFF;
7707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        packet.order(ByteOrder.BIG_ENDIAN);
7727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // check to see if we need to parse L2, IP, and UDP encaps
7747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        if (pktType == ENCAP_L2) {
775b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
7762677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT,
7772677b1957b444e2dae5737feee989109b811547cHugo Benichi                        "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
778b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            }
779b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti
7807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte[] l2dst = new byte[6];
7817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte[] l2src = new byte[6];
7827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(l2dst);
7847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(l2src);
7857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short l2type = packet.getShort();
7877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
7886241874355c0e0d9ff04e993ad1d522c66b8c50bHugo Benichi            if (l2type != OsConstants.ETH_P_IP) {
7892677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE,
7902677b1957b444e2dae5737feee989109b811547cHugo Benichi                        "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
7916241874355c0e0d9ff04e993ad1d522c66b8c50bHugo Benichi            }
7927da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
7937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
794fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        if (pktType <= ENCAP_L3) {
795b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
7962677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT,
7972677b1957b444e2dae5737feee989109b811547cHugo Benichi                        "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
798b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            }
799b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti
8007f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            byte ipTypeAndLength = packet.get();
8017f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
8027f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            if (ipVersion != 4) {
8032677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(
8042677b1957b444e2dae5737feee989109b811547cHugo Benichi                        DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
8057f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            }
8067f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti
8077da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // System.out.println("ipType is " + ipType);
8087da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipDiffServicesField = packet.get();
8097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short ipTotalLength = packet.getShort();
8107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short ipIdentification = packet.getShort();
8117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipFlags = packet.get();
8127da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipFragOffset = packet.get();
8137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipTTL = packet.get();
8147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            byte ipProto = packet.get();
8157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short ipChksm = packet.getShort();
8167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            ipSrc = readIpAddress(packet);
8187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            ipDst = readIpAddress(packet);
8197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
820496906ee7008b72619f230c65f103533d4d2d68aErik Kline            if (ipProto != IP_TYPE_UDP) {
8212677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(
8222677b1957b444e2dae5737feee989109b811547cHugo Benichi                        DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
823496906ee7008b72619f230c65f103533d4d2d68aErik Kline            }
8247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
825b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            // Skip options. This cannot cause us to read beyond the end of the buffer because the
826b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
827b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            // MIN_PACKET_LENGTH_L3.
8287f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            int optionWords = ((ipTypeAndLength & 0x0f) - 5);
8297f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            for (int i = 0; i < optionWords; i++) {
8307f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti                packet.getInt();
8317f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti            }
8327f7cc6115914b4a0ebd99c5d77db8f571195a1fbLorenzo Colitti
8337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            // assume UDP
8347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpSrcPort = packet.getShort();
8357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpDstPort = packet.getShort();
8367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpLen = packet.getShort();
8377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            short udpChkSum = packet.getShort();
8387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
839b19238c48814c5a1438b1238794e121876ae89abErik Kline            // Only accept packets to or from the well-known client port (expressly permitting
840b19238c48814c5a1438b1238794e121876ae89abErik Kline            // packets from ports other than the well-known server port; http://b/24687559), and
841b19238c48814c5a1438b1238794e121876ae89abErik Kline            // server-to-server packets, e.g. for relays.
842b19238c48814c5a1438b1238794e121876ae89abErik Kline            if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
843b19238c48814c5a1438b1238794e121876ae89abErik Kline                !isPacketServerToServer(udpSrcPort, udpDstPort)) {
844f55c9c1781d1bf24360bc1cb3d2c41fb8a9d6107Lorenzo Colitti                // This should almost never happen because we use SO_ATTACH_FILTER on the packet
845f55c9c1781d1bf24360bc1cb3d2c41fb8a9d6107Lorenzo Colitti                // socket to drop packets that don't have the right source ports. However, it's
846f55c9c1781d1bf24360bc1cb3d2c41fb8a9d6107Lorenzo Colitti                // possible that a packet arrives between when the socket is bound and when the
847f55c9c1781d1bf24360bc1cb3d2c41fb8a9d6107Lorenzo Colitti                // filter is set. http://b/26696823 .
8482677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT,
8492677b1957b444e2dae5737feee989109b811547cHugo Benichi                        "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
850496906ee7008b72619f230c65f103533d4d2d68aErik Kline            }
8517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
8527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
853b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti        // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
854b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti        if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
8552677b1957b444e2dae5737feee989109b811547cHugo Benichi            throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT,
8562677b1957b444e2dae5737feee989109b811547cHugo Benichi                        "Invalid type or BOOTP packet too short, %d < %d",
857496906ee7008b72619f230c65f103533d4d2d68aErik Kline                        packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
858b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti        }
859b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti
8607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte type = packet.get();
8617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte hwType = packet.get();
862d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        int addrLen = packet.get() & 0xff;
8637da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte hops = packet.get();
8647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        transactionId = packet.getInt();
8653e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti        secs = packet.getShort();
8667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        short bootpFlags = packet.getShort();
8677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        boolean broadcast = (bootpFlags & 0x8000) != 0;
8687da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        byte[] ipv4addr = new byte[4];
8697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        try {
8717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(ipv4addr);
87251697effe9567a144532190ad534370a00c15996Lorenzo Colitti            clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
8737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(ipv4addr);
87451697effe9567a144532190ad534370a00c15996Lorenzo Colitti            yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
8757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(ipv4addr);
87651697effe9567a144532190ad534370a00c15996Lorenzo Colitti            nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
8777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            packet.get(ipv4addr);
87851697effe9567a144532190ad534370a00c15996Lorenzo Colitti            relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
8797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        } catch (UnknownHostException ex) {
8802677b1957b444e2dae5737feee989109b811547cHugo Benichi            throw new ParseException(DhcpErrorEvent.L3_INVALID_IP,
8812677b1957b444e2dae5737feee989109b811547cHugo Benichi                    "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
8827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
8837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
884d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        // Some DHCP servers have been known to announce invalid client hardware address values such
885d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
886d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        // all but only checks that the interface MAC address matches the first bytes of the address
887d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
888d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
889d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        // TODO: evaluate whether to make this test more liberal.
890d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        if (addrLen > HWADDR_LEN) {
891d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti            addrLen = ETHER_BROADCAST.length;
892d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti        }
893d64144a37ca0a6f341c0092cc04271831ff5f90dLorenzo Colitti
8947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        clientMac = new byte[addrLen];
8957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        packet.get(clientMac);
8967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
8977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // skip over address padding (16 octets allocated)
8987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        packet.position(packet.position() + (16 - addrLen)
8997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        + 64    // skip server host name (64 chars)
9007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                        + 128); // skip boot file name (128 chars)
9017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
902006e0613016c1a0e0627f992f5a93a7b7198edbaHugo Benichi        // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
903006e0613016c1a0e0627f992f5a93a7b7198edbaHugo Benichi        if (packet.remaining() < 4) {
904006e0613016c1a0e0627f992f5a93a7b7198edbaHugo Benichi            throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
905006e0613016c1a0e0627f992f5a93a7b7198edbaHugo Benichi        }
9067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
907006e0613016c1a0e0627f992f5a93a7b7198edbaHugo Benichi        int dhcpMagicCookie = packet.getInt();
908496906ee7008b72619f230c65f103533d4d2d68aErik Kline        if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
9092677b1957b444e2dae5737feee989109b811547cHugo Benichi            throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
9102677b1957b444e2dae5737feee989109b811547cHugo Benichi                    "Bad magic cookie 0x%08x, should be 0x%08x",
9112677b1957b444e2dae5737feee989109b811547cHugo Benichi                    dhcpMagicCookie, DHCP_MAGIC_COOKIE);
912496906ee7008b72619f230c65f103533d4d2d68aErik Kline        }
9137da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
9147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        // parse options
9157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        boolean notFinishedOptions = true;
9167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
9177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        while ((packet.position() < packet.limit()) && notFinishedOptions) {
9186241874355c0e0d9ff04e993ad1d522c66b8c50bHugo Benichi            final byte optionType = packet.get(); // cannot underflow because position < limit
919b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            try {
920b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                if (optionType == DHCP_OPTION_END) {
921b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                    notFinishedOptions = false;
922b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                } else if (optionType == DHCP_OPTION_PAD) {
923b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                    // The pad option doesn't have a length field. Nothing to do.
924b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                } else {
925b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                    int optionLen = packet.get() & 0xFF;
926b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                    int expectedLen = 0;
927b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti
928b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                    switch(optionType) {
929b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_SUBNET_MASK:
930b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            netMask = readIpAddress(packet);
931b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 4;
932b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
933b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_ROUTER:
934025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
935025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti                                gateways.add(readIpAddress(packet));
936025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti                            }
937b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
938b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_DNS_SERVER:
939b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
940b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                                dnsServers.add(readIpAddress(packet));
941b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            }
942b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
943b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_HOST_NAME:
944b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = optionLen;
945a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti                            hostName = readAsciiString(packet, optionLen, false);
946b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
947b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_MTU:
948b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 2;
94977fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti                            mtu = packet.getShort();
950b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
951b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_DOMAIN_NAME:
952b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = optionLen;
953a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti                            domainName = readAsciiString(packet, optionLen, false);
954b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
955b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_BROADCAST_ADDRESS:
956b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            bcAddr = readIpAddress(packet);
957b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 4;
958b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
959b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_REQUESTED_IP:
960b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            requestedIp = readIpAddress(packet);
961b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 4;
962b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
963b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_LEASE_TIME:
964b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            leaseTime = Integer.valueOf(packet.getInt());
965b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 4;
966b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
967b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_MESSAGE_TYPE:
968b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            dhcpType = packet.get();
969b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 1;
970b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
971b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_SERVER_IDENTIFIER:
972b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            serverIdentifier = readIpAddress(packet);
973b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 4;
974b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
975b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_PARAMETER_LIST:
976b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedParams = new byte[optionLen];
977b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            packet.get(expectedParams);
978b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = optionLen;
979b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
980b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_MESSAGE:
981b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = optionLen;
982a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti                            message = readAsciiString(packet, optionLen, false);
983b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
984b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_MAX_MESSAGE_SIZE:
985b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 2;
986b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            maxMessageSize = Short.valueOf(packet.getShort());
987b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
988b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_RENEWAL_TIME:
989b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 4;
990b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            T1 = Integer.valueOf(packet.getInt());
991b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
992b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_REBINDING_TIME:
993b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = 4;
994b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            T2 = Integer.valueOf(packet.getInt());
995b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
996b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_VENDOR_CLASS_ID:
997b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = optionLen;
998b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                            // Embedded nulls are safe as this does not get passed to netd.
999a12bde35672c45af7bca8170ee1a3b3370bec30eLorenzo Colitti                            vendorId = readAsciiString(packet, optionLen, true);
1000b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            break;
1001b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        case DHCP_CLIENT_IDENTIFIER: { // Client identifier
1002b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            byte[] id = new byte[optionLen];
1003b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            packet.get(id);
1004b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            expectedLen = optionLen;
1005b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        } break;
1006b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                        case DHCP_VENDOR_INFO:
1007b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                            expectedLen = optionLen;
1008b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                            // Embedded nulls are safe as this does not get passed to netd.
1009b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                            vendorInfo = readAsciiString(packet, optionLen, true);
1010b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti                            break;
1011b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                        default:
1012b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            // ignore any other parameters
1013b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            for (int i = 0; i < optionLen; i++) {
1014b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                                expectedLen++;
1015b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                                byte throwaway = packet.get();
1016b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                            }
1017b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                    }
1018b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti
1019b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                    if (expectedLen != optionLen) {
10202677b1957b444e2dae5737feee989109b811547cHugo Benichi                        final int errorCode = DhcpErrorEvent.errorCodeWithOption(
10216241874355c0e0d9ff04e993ad1d522c66b8c50bHugo Benichi                                DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
10222677b1957b444e2dae5737feee989109b811547cHugo Benichi                        throw new ParseException(errorCode,
10232677b1957b444e2dae5737feee989109b811547cHugo Benichi                                "Invalid length %d for option %d, expected %d",
1024496906ee7008b72619f230c65f103533d4d2d68aErik Kline                                optionLen, optionType, expectedLen);
1025b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti                    }
10267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                }
1027b05c9234e644b9648ff21c991ef010df10783b0cLorenzo Colitti            } catch (BufferUnderflowException e) {
10282677b1957b444e2dae5737feee989109b811547cHugo Benichi                final int errorCode = DhcpErrorEvent.errorCodeWithOption(
10292677b1957b444e2dae5737feee989109b811547cHugo Benichi                        DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
10302677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(errorCode, "BufferUnderflowException");
10317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            }
10327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
10337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
10347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket newPacket;
10357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
10367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        switch(dhcpType) {
1037496906ee7008b72619f230c65f103533d4d2d68aErik Kline            case (byte) 0xFF:
10382677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
10392677b1957b444e2dae5737feee989109b811547cHugo Benichi                        "No DHCP message type option");
10407da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_DISCOVER:
10417da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpDiscoverPacket(
10423e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti                    transactionId, secs, clientMac, broadcast);
10437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
10447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_OFFER:
10457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpOfferPacket(
1046f68edb16116307553059a889ef456227a9697918Lorenzo Colitti                    transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
10477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
10487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_REQUEST:
10497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpRequestPacket(
10503e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti                    transactionId, secs, clientIp, clientMac, broadcast);
10517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
10527da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_DECLINE:
10537da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpDeclinePacket(
10543e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
10557da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    clientMac);
10567da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
10577da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_ACK:
10587da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpAckPacket(
1059f68edb16116307553059a889ef456227a9697918Lorenzo Colitti                    transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
10607da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
10617da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_NAK:
10627da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpNakPacket(
10633e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
10647da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    clientMac);
10657da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
10667da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            case DHCP_MESSAGE_TYPE_INFORM:
10677da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                newPacket = new DhcpInformPacket(
10683e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
10697da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                    clientMac);
10707da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt                break;
10717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            default:
10722677b1957b444e2dae5737feee989109b811547cHugo Benichi                throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE,
10732677b1957b444e2dae5737feee989109b811547cHugo Benichi                        "Unimplemented DHCP type %d", dhcpType);
10747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        }
10757da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
10767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mBroadcastAddress = bcAddr;
10777da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mDnsServers = dnsServers;
10787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mDomainName = domainName;
1079025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        newPacket.mGateways = gateways;
10807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mHostName = hostName;
10817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mLeaseTime = leaseTime;
10827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mMessage = message;
1083fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        newPacket.mMtu = mtu;
10847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mRequestedIp = requestedIp;
10857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mRequestedParams = expectedParams;
10867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mServerIdentifier = serverIdentifier;
10877da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        newPacket.mSubnetMask = netMask;
1088fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        newPacket.mMaxMessageSize = maxMessageSize;
1089fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        newPacket.mT1 = T1;
1090fe5ffce09c4a163ee9a190aedc9fd7cea38a576fLorenzo Colitti        newPacket.mT2 = T2;
109186bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        newPacket.mVendorId = vendorId;
1092b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti        newPacket.mVendorInfo = vendorInfo;
10937da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return newPacket;
10947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
10957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
10967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
109786bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti     * Parse a packet from an array of bytes, stopping at the given length.
10987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
109986bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti    public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
1100496906ee7008b72619f230c65f103533d4d2d68aErik Kline            throws ParseException {
110186bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
1102e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi        try {
1103e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi            return decodeFullPacket(buffer, pktType);
1104e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi        } catch (ParseException e) {
1105e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi            throw e;
1106e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi        } catch (Exception e) {
1107e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi            throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
1108e0ea7fecd63002ac2d3df18490fd1c16578d1935Hugo Benichi        }
11097da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
11107da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
11117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
111286bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti     *  Construct a DhcpResults object from a DHCP reply packet.
111386bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti     */
111486bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti    public DhcpResults toDhcpResults() {
111586bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        Inet4Address ipAddress = mYourIp;
1116f68edb16116307553059a889ef456227a9697918Lorenzo Colitti        if (ipAddress.equals(Inet4Address.ANY)) {
111786bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti            ipAddress = mClientIp;
1118f68edb16116307553059a889ef456227a9697918Lorenzo Colitti            if (ipAddress.equals(Inet4Address.ANY)) {
111986bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti                return null;
112086bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti            }
112186bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        }
112286bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti
112386bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        int prefixLength;
112486bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        if (mSubnetMask != null) {
112586bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti            try {
112686bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti                prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask);
112786bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti            } catch (IllegalArgumentException e) {
112886bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti                // Non-contiguous netmask.
112986bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti                return null;
113086bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti            }
113186bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        } else {
113286bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti            prefixLength = NetworkUtils.getImplicitNetmask(ipAddress);
113386bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        }
113486bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti
113586bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        DhcpResults results = new DhcpResults();
113686bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        try {
113786bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti            results.ipAddress = new LinkAddress(ipAddress, prefixLength);
113886bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        } catch (IllegalArgumentException e) {
113986bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti            return null;
114086bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        }
1141025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti
1142025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        if (mGateways.size() > 0) {
1143025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti            results.gateway = mGateways.get(0);
1144025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        }
1145025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti
114686bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        results.dnsServers.addAll(mDnsServers);
114786bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        results.domains = mDomainName;
114886bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        results.serverAddress = mServerIdentifier;
1149b0b3d0bcfb0af678d4c85bec63722f976ffb01cfLorenzo Colitti        results.vendorInfo = mVendorInfo;
1150d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti        results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
115177fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti        results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
115277fdf23d6f7831c09fc43d206b346e273ebe266aLorenzo Colitti
115386bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti        return results;
115486bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti    }
115586bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti
115686bff86778d006d59a36bb10c7a577d982934402Lorenzo Colitti    /**
1157d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti     * Returns the parsed lease time, in milliseconds, or 0 for infinite.
1158d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti     */
1159d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti    public long getLeaseTimeMillis() {
1160d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti        // dhcpcd treats the lack of a lease time option as an infinite lease.
1161d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti        if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) {
1162d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti            return 0;
1163d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti        } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) {
1164d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti            return MINIMUM_LEASE * 1000;
1165d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti        } else {
1166d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti            return (mLeaseTime & 0xffffffffL) * 1000;
1167d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti        }
1168d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti    }
1169d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti
1170d973537ee1bd013b4233d3369d66821e124a2e65Lorenzo Colitti    /**
11717da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-DISCOVER packet from the required specified
11727da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * parameters.
11737da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
11747da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
11753e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti        short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
11767da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket pkt = new DhcpDiscoverPacket(
11773e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti            transactionId, secs, clientMac, broadcast);
11787da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mRequestedParams = expectedParams;
11797da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
11807da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
11817da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
11827da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
11837da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-OFFER packet from the required specified
11847da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * parameters.
11857da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
11867da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildOfferPacket(int encap, int transactionId,
118751697effe9567a144532190ad534370a00c15996Lorenzo Colitti        boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
118851697effe9567a144532190ad534370a00c15996Lorenzo Colitti        byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
1189025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        List<Inet4Address> gateways, List<Inet4Address> dnsServers,
119051697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address dhcpServerIdentifier, String domainName) {
11917da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket pkt = new DhcpOfferPacket(
1192f68edb16116307553059a889ef456227a9697918Lorenzo Colitti            transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
1193025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        pkt.mGateways = gateways;
11947da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mDnsServers = dnsServers;
11957da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mLeaseTime = timeout;
11967da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mDomainName = domainName;
11977da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mServerIdentifier = dhcpServerIdentifier;
11987da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mSubnetMask = netMask;
11997da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mBroadcastAddress = bcAddr;
12007da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
12017da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
12027da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
12037da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
12047da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-ACK packet from the required specified parameters.
12057da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
12067da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildAckPacket(int encap, int transactionId,
120751697effe9567a144532190ad534370a00c15996Lorenzo Colitti        boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
120851697effe9567a144532190ad534370a00c15996Lorenzo Colitti        byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
1209025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        List<Inet4Address> gateways, List<Inet4Address> dnsServers,
121051697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address dhcpServerIdentifier, String domainName) {
12117da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        DhcpPacket pkt = new DhcpAckPacket(
1212f68edb16116307553059a889ef456227a9697918Lorenzo Colitti            transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
1213025f4a5aae1660eda6406703771995010d9de990Lorenzo Colitti        pkt.mGateways = gateways;
12147da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mDnsServers = dnsServers;
12157da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mLeaseTime = timeout;
12167da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mDomainName = domainName;
12177da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mSubnetMask = netMask;
12187da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mServerIdentifier = dhcpServerIdentifier;
12197da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mBroadcastAddress = bcAddr;
12207da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
12217da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
12227da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
12237da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
12247da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-NAK packet from the required specified parameters.
12257da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
12267da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildNakPacket(int encap, int transactionId,
122751697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) {
12283e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti        DhcpPacket pkt = new DhcpNakPacket(transactionId, (short) 0, clientIpAddr,
12297da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            serverIpAddr, serverIpAddr, serverIpAddr, mac);
12307da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mMessage = "requested address not available";
12317da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mRequestedIp = clientIpAddr;
12327da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
12337da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
12347da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt
12357da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    /**
12367da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     * Builds a DHCP-REQUEST packet from the required specified parameters.
12377da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt     */
12387da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    public static ByteBuffer buildRequestPacket(int encap,
12393e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti        int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
124051697effe9567a144532190ad534370a00c15996Lorenzo Colitti        byte[] clientMac, Inet4Address requestedIpAddress,
124151697effe9567a144532190ad534370a00c15996Lorenzo Colitti        Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
12423e979321a5d96b9e2688f67ef0f936602c0f7e5aLorenzo Colitti        DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
12437da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt            clientMac, broadcast);
12447da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mRequestedIp = requestedIpAddress;
12457da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mServerIdentifier = serverIdentifier;
12467da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mHostName = hostName;
12477da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        pkt.mRequestedParams = requestedParams;
12487da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
12497da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt        return result;
12507da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt    }
12517da02ad3b7a8a0b13a2ccc84e666baa8e6370482Stan Chesnutt}
1252