Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1885805a authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN
Browse files

Add fields to DHCP packets for server use-case

Also add DhcpReleasePacket

Test: runtest -x DhcpPacketTest.java, manual: still obtains IP
Bug: b/109584964
Change-Id: I19e68e8857646555ea56995880979a8a722757d7
parent 12da4a5e
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -23,11 +23,18 @@ import java.nio.ByteBuffer;
 * This class implements the DHCP-DISCOVER packet.
 */
class DhcpDiscoverPacket extends DhcpPacket {
    /**
     * The IP address of the client which sent this packet.
     */
    final Inet4Address mSrcIp;

    /**
     * Generates a DISCOVER packet with the specified parameters.
     */
    DhcpDiscoverPacket(int transId, short secs, byte[] clientMac, boolean broadcast) {
        super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
    DhcpDiscoverPacket(int transId, short secs, Inet4Address relayIp, byte[] clientMac,
            boolean broadcast, Inet4Address srcIp) {
        super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, relayIp, clientMac, broadcast);
        mSrcIp = srcIp;
    }

    public String toString() {
@@ -41,8 +48,8 @@ class DhcpDiscoverPacket extends DhcpPacket {
     */
    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
        fillInPacket(encap, INADDR_BROADCAST, INADDR_ANY, destUdp,
                srcUdp, result, DHCP_BOOTREQUEST, mBroadcast);
        fillInPacket(encap, INADDR_BROADCAST, mSrcIp, destUdp, srcUdp, result, DHCP_BOOTREQUEST,
                mBroadcast);
        result.flip();
        return result;
    }
+7 −9
Original line number Diff line number Diff line
@@ -26,11 +26,9 @@ class DhcpNakPacket extends DhcpPacket {
    /**
     * Generates a NAK packet with the specified parameters.
     */
    DhcpNakPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
                  Inet4Address nextIp, Inet4Address relayIp,
                  byte[] clientMac) {
        super(transId, secs, INADDR_ANY, INADDR_ANY, nextIp, relayIp,
            clientMac, false);
    DhcpNakPacket(int transId, short secs, Inet4Address nextIp, Inet4Address relayIp,
            byte[] clientMac, boolean broadcast) {
        super(transId, secs, INADDR_ANY, INADDR_ANY, nextIp, relayIp, clientMac, broadcast);
    }

    public String toString() {
@@ -43,11 +41,11 @@ class DhcpNakPacket extends DhcpPacket {
     */
    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
        Inet4Address destIp = mClientIp;
        Inet4Address srcIp = mYourIp;
        // Constructor does not set values for layers <= 3: use empty values
        Inet4Address destIp = INADDR_ANY;
        Inet4Address srcIp = INADDR_ANY;

        fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result,
            DHCP_BOOTREPLY, mBroadcast);
        fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result, DHCP_BOOTREPLY, mBroadcast);
        result.flip();
        return result;
    }
+71 −31
Original line number Diff line number Diff line
package android.net.dhcp;

import android.annotation.Nullable;
import android.net.DhcpResults;
import android.net.LinkAddress;
import android.net.NetworkUtils;
@@ -204,6 +205,7 @@ public abstract class DhcpPacket {
    protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
    protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
    protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
    protected static final byte DHCP_MESSAGE_TYPE_RELEASE = 7;
    protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;

    /**
@@ -252,6 +254,7 @@ public abstract class DhcpPacket {
     * DHCP Optional Type: DHCP Client Identifier
     */
    protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
    protected byte[] mClientId;

    /**
     * DHCP zero-length option code: pad
@@ -281,7 +284,7 @@ public abstract class DhcpPacket {
    protected final Inet4Address mClientIp;
    protected final Inet4Address mYourIp;
    private final Inet4Address mNextIp;
    private final Inet4Address mRelayIp;
    protected final Inet4Address mRelayIp;

    /**
     * Does the client request a broadcast response?
@@ -338,13 +341,28 @@ public abstract class DhcpPacket {
        return mClientMac;
    }

    // TODO: refactor DhcpClient to set clientId when constructing packets and remove
    // hasExplicitClientId logic
    /**
     * Returns the client ID. This follows RFC 2132 and is based on the hardware address.
     * Returns whether a client ID was set in the options for this packet.
     */
    public boolean hasExplicitClientId() {
        return mClientId != null;
    }

    /**
     * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID
     * based on the hardware address.
     */
    public byte[] getClientId() {
        byte[] clientId = new byte[mClientMac.length + 1];
        final byte[] clientId;
        if (hasExplicitClientId()) {
            clientId = Arrays.copyOf(mClientId, mClientId.length);
        } else {
            clientId = new byte[mClientMac.length + 1];
            clientId[0] = CLIENT_ID_ETHER;
            System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length);
        }
        return clientId;
    }

@@ -531,8 +549,10 @@ public abstract class DhcpPacket {

    /**
     * Adds an optional parameter containing an array of bytes.
     *
     * <p>This method is a no-op if the payload argument is null.
     */
    protected static void addTlv(ByteBuffer buf, byte type, byte[] payload) {
    protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) {
        if (payload != null) {
            if (payload.length > MAX_OPTION_LEN) {
                throw new IllegalArgumentException("DHCP option too long: "
@@ -546,8 +566,10 @@ public abstract class DhcpPacket {

    /**
     * Adds an optional parameter containing an IP address.
     *
     * <p>This method is a no-op if the address argument is null.
     */
    protected static void addTlv(ByteBuffer buf, byte type, Inet4Address addr) {
    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) {
        if (addr != null) {
            addTlv(buf, type, addr.getAddress());
        }
@@ -555,8 +577,10 @@ public abstract class DhcpPacket {

    /**
     * Adds an optional parameter containing a list of IP addresses.
     *
     * <p>This method is a no-op if the addresses argument is null or empty.
     */
    protected static void addTlv(ByteBuffer buf, byte type, List<Inet4Address> addrs) {
    protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) {
        if (addrs == null || addrs.size() == 0) return;

        int optionLen = 4 * addrs.size();
@@ -574,9 +598,11 @@ public abstract class DhcpPacket {
    }

    /**
     * Adds an optional parameter containing a short integer
     * Adds an optional parameter containing a short integer.
     *
     * <p>This method is a no-op if the value argument is null.
     */
    protected static void addTlv(ByteBuffer buf, byte type, Short value) {
    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) {
        if (value != null) {
            buf.put(type);
            buf.put((byte) 2);
@@ -585,9 +611,11 @@ public abstract class DhcpPacket {
    }

    /**
     * Adds an optional parameter containing a simple integer
     * Adds an optional parameter containing a simple integer.
     *
     * <p>This method is a no-op if the value argument is null.
     */
    protected static void addTlv(ByteBuffer buf, byte type, Integer value) {
    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) {
        if (value != null) {
            buf.put(type);
            buf.put((byte) 4);
@@ -597,14 +625,18 @@ public abstract class DhcpPacket {

    /**
     * Adds an optional parameter containing an ASCII string.
     *
     * <p>This method is a no-op if the string argument is null.
     */
    protected static void addTlv(ByteBuffer buf, byte type, String str) {
    protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) {
        if (str != null) {
            try {
                addTlv(buf, type, str.getBytes("US-ASCII"));
            } catch (UnsupportedEncodingException e) {
                throw new IllegalArgumentException("String is not US-ASCII: " + str);
            }
        }
    }

    /**
     * Adds the special end-of-optional-parameters indicator.
@@ -740,6 +772,7 @@ public abstract class DhcpPacket {
        Inet4Address nextIp;
        Inet4Address relayIp;
        byte[] clientMac;
        byte[] clientId = null;
        List<Inet4Address> dnsServers = new ArrayList<>();
        List<Inet4Address> gateways = new ArrayList<>();  // aka router
        Inet4Address serverIdentifier = null;
@@ -1038,8 +1071,8 @@ public abstract class DhcpPacket {
                throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
                        "No DHCP message type option");
            case DHCP_MESSAGE_TYPE_DISCOVER:
                newPacket = new DhcpDiscoverPacket(
                    transactionId, secs, clientMac, broadcast);
                newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac,
                        broadcast, ipSrc);
                break;
            case DHCP_MESSAGE_TYPE_OFFER:
                newPacket = new DhcpOfferPacket(
@@ -1047,7 +1080,7 @@ public abstract class DhcpPacket {
                break;
            case DHCP_MESSAGE_TYPE_REQUEST:
                newPacket = new DhcpRequestPacket(
                    transactionId, secs, clientIp, clientMac, broadcast);
                    transactionId, secs, clientIp, relayIp, clientMac, broadcast);
                break;
            case DHCP_MESSAGE_TYPE_DECLINE:
                newPacket = new DhcpDeclinePacket(
@@ -1060,8 +1093,15 @@ public abstract class DhcpPacket {
                break;
            case DHCP_MESSAGE_TYPE_NAK:
                newPacket = new DhcpNakPacket(
                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
                    clientMac);
                        transactionId, secs, nextIp, relayIp, clientMac, broadcast);
                break;
            case DHCP_MESSAGE_TYPE_RELEASE:
                if (serverIdentifier == null) {
                    throw new ParseException(DhcpErrorEvent.MISC_ERROR,
                            "DHCPRELEASE without server identifier");
                }
                newPacket = new DhcpReleasePacket(
                        transactionId, serverIdentifier, clientIp, relayIp, clientMac);
                break;
            case DHCP_MESSAGE_TYPE_INFORM:
                newPacket = new DhcpInformPacket(
@@ -1074,6 +1114,7 @@ public abstract class DhcpPacket {
        }

        newPacket.mBroadcastAddress = bcAddr;
        newPacket.mClientId = clientId;
        newPacket.mDnsServers = dnsServers;
        newPacket.mDomainName = domainName;
        newPacket.mGateways = gateways;
@@ -1173,8 +1214,8 @@ public abstract class DhcpPacket {
     */
    public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
        short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
        DhcpPacket pkt = new DhcpDiscoverPacket(
            transactionId, secs, clientMac, broadcast);
        DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */,
                clientMac, broadcast, INADDR_ANY /* srcIp */);
        pkt.mRequestedParams = expectedParams;
        return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
    }
@@ -1223,12 +1264,11 @@ public abstract class DhcpPacket {
    /**
     * Builds a DHCP-NAK packet from the required specified parameters.
     */
    public static ByteBuffer buildNakPacket(int encap, int transactionId,
        Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) {
        DhcpPacket pkt = new DhcpNakPacket(transactionId, (short) 0, clientIpAddr,
            serverIpAddr, serverIpAddr, serverIpAddr, mac);
        pkt.mMessage = "requested address not available";
        pkt.mRequestedIp = clientIpAddr;
    public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr,
            byte[] mac, boolean broadcast, String message) {
        DhcpPacket pkt = new DhcpNakPacket(
                transactionId, (short) 0, serverIpAddr, serverIpAddr, mac, broadcast);
        pkt.mMessage = message;
        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
    }

@@ -1240,7 +1280,7 @@ public abstract class DhcpPacket {
        byte[] clientMac, Inet4Address requestedIpAddress,
        Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
        DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
            clientMac, broadcast);
                INADDR_ANY /* relayIp */, clientMac, broadcast);
        pkt.mRequestedIp = requestedIpAddress;
        pkt.mServerIdentifier = serverIdentifier;
        pkt.mHostName = hostName;
+58 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net.dhcp;

import java.net.Inet4Address;
import java.nio.ByteBuffer;

/**
 * Implements DHCP-RELEASE
 */
class DhcpReleasePacket extends DhcpPacket {

    final Inet4Address mClientAddr;

    /**
     * Generates a RELEASE packet with the specified parameters.
     */
    public DhcpReleasePacket(int transId, Inet4Address serverId, Inet4Address clientAddr,
            Inet4Address relayIp, byte[] clientMac) {
        super(transId, (short)0, clientAddr, INADDR_ANY /* yourIp */, INADDR_ANY /* nextIp */,
                relayIp, clientMac, false /* broadcast */);
        mServerIdentifier = serverId;
        mClientAddr = clientAddr;
    }


    @Override
    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
        fillInPacket(encap, mServerIdentifier /* destIp */, mClientIp /* srcIp */, destUdp, srcUdp,
                result, DHCP_BOOTREPLY, mBroadcast);
        result.flip();
        return result;
    }

    @Override
    void finishPacket(ByteBuffer buffer) {
        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_RELEASE);
        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
        addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
        addCommonClientTlvs(buffer);
        addTlvEnd(buffer);
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -28,9 +28,9 @@ class DhcpRequestPacket extends DhcpPacket {
    /**
     * Generates a REQUEST packet with the specified parameters.
     */
    DhcpRequestPacket(int transId, short secs, Inet4Address clientIp, byte[] clientMac,
                      boolean broadcast) {
        super(transId, secs, clientIp, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
    DhcpRequestPacket(int transId, short secs, Inet4Address clientIp, Inet4Address relayIp,
            byte[] clientMac, boolean broadcast) {
        super(transId, secs, clientIp, INADDR_ANY, INADDR_ANY, relayIp, clientMac, broadcast);
    }

    public String toString() {