From 1ff7c3ef71e6e82464105c3e0f439b380069b60e Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 1 May 2025 10:31:58 -0700 Subject: [PATCH 1/3] Move Dhcp6*Packet.java to staticlibs For use in tests. This CL won't build by itself mv NetworkStack/src/android/net/dhcp6/Dhcp6*Packet.java \ Connectivity/staticlibs/device/com/android/net/module/util/dhcp6 Test: TH Flag: EXEMPT mainline Bug: 1000001 Change-Id: Ie072f2f20ecfbf23f77606dd064e0f6fbd7c2232 --- .../util/dhcp6/Dhcp6AdvertisePacket.java | 55 ++ .../net/module/util/dhcp6/Dhcp6Packet.java | 737 ++++++++++++++++++ .../module/util/dhcp6/Dhcp6RebindPacket.java | 56 ++ .../module/util/dhcp6/Dhcp6RenewPacket.java | 57 ++ .../module/util/dhcp6/Dhcp6ReplyPacket.java | 60 ++ .../module/util/dhcp6/Dhcp6RequestPacket.java | 57 ++ .../module/util/dhcp6/Dhcp6SolicitPacket.java | 59 ++ 7 files changed, 1081 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6AdvertisePacket.java create mode 100644 staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java create mode 100644 staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RebindPacket.java create mode 100644 staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RenewPacket.java create mode 100644 staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6ReplyPacket.java create mode 100644 staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RequestPacket.java create mode 100644 staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6SolicitPacket.java diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6AdvertisePacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6AdvertisePacket.java new file mode 100644 index 0000000000..263ab5ff04 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6AdvertisePacket.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023 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.dhcp6; + +import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; + +import androidx.annotation.NonNull; + +import java.nio.ByteBuffer; + +/** + * DHCPv6 ADVERTISE packet class, a server sends an Advertise message to indicate that it's + * available for DHCP service, in response to a Solicit message received from a client. + * + * https://tools.ietf.org/html/rfc8415#page-24 + */ +public class Dhcp6AdvertisePacket extends Dhcp6Packet { + /** + * Generates an advertise packet with the specified parameters. + */ + Dhcp6AdvertisePacket(int transId, @NonNull final byte[] clientDuid, + @NonNull final byte[] serverDuid, final byte[] iapd) { + super(transId, 0 /* elapsedTime */, clientDuid, serverDuid, iapd); + } + + /** + * Build a DHCPv6 Advertise message with the specific parameters. + */ + public ByteBuffer buildPacket() { + final ByteBuffer packet = ByteBuffer.allocate(DHCP_MAX_LENGTH); + final int msgTypeAndTransId = (DHCP6_MESSAGE_TYPE_ADVERTISE << 24) | mTransId; + packet.putInt(msgTypeAndTransId); + + addTlv(packet, DHCP6_CLIENT_IDENTIFIER, mClientDuid); + addTlv(packet, DHCP6_SERVER_IDENTIFIER, mServerDuid); + addTlv(packet, DHCP6_IA_PD, mIaPd); + + packet.flip(); + return packet; + } +} diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java new file mode 100644 index 0000000000..ff7b036d61 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java @@ -0,0 +1,737 @@ +/* + * Copyright (C) 2023 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.dhcp6; + +import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_OPTION_LEN; + +import android.net.MacAddress; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.HexDump; +import com.android.net.module.util.Struct; +import com.android.net.module.util.structs.IaPdOption; +import com.android.net.module.util.structs.IaPrefixOption; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.OptionalInt; + +/** + * Defines basic data and operations needed to build and use packets for the + * DHCPv6 protocol. Subclasses create the specific packets used at each + * stage of the negotiation. + * + * @hide + */ +public class Dhcp6Packet { + private static final String TAG = Dhcp6Packet.class.getSimpleName(); + /** + * DHCPv6 Message Type. + */ + public static final byte DHCP6_MESSAGE_TYPE_SOLICIT = 1; + public static final byte DHCP6_MESSAGE_TYPE_ADVERTISE = 2; + public static final byte DHCP6_MESSAGE_TYPE_REQUEST = 3; + public static final byte DHCP6_MESSAGE_TYPE_CONFIRM = 4; + public static final byte DHCP6_MESSAGE_TYPE_RENEW = 5; + public static final byte DHCP6_MESSAGE_TYPE_REBIND = 6; + public static final byte DHCP6_MESSAGE_TYPE_REPLY = 7; + public static final byte DHCP6_MESSAGE_TYPE_RELEASE = 8; + public static final byte DHCP6_MESSAGE_TYPE_DECLINE = 9; + public static final byte DHCP6_MESSAGE_TYPE_RECONFIGURE = 10; + public static final byte DHCP6_MESSAGE_TYPE_INFORMATION_REQUEST = 11; + public static final byte DHCP6_MESSAGE_TYPE_RELAY_FORW = 12; + public static final byte DHCP6_MESSAGE_TYPE_RELAY_REPL = 13; + + /** + * DHCPv6 Optional Type: Client Identifier. + * DHCPv6 message from client must have this option. + */ + public static final byte DHCP6_CLIENT_IDENTIFIER = 1; + @NonNull + protected final byte[] mClientDuid; + + /** + * DHCPv6 Optional Type: Server Identifier. + */ + public static final byte DHCP6_SERVER_IDENTIFIER = 2; + protected final byte[] mServerDuid; + + /** + * DHCPv6 Optional Type: Option Request Option. + */ + public static final byte DHCP6_OPTION_REQUEST_OPTION = 6; + + /** + * DHCPv6 Optional Type: Elapsed time. + * This time is expressed in hundredths of a second. + */ + public static final byte DHCP6_ELAPSED_TIME = 8; + protected final int mElapsedTime; + + /** + * DHCPv6 Optional Type: Status Code. + */ + public static final byte DHCP6_STATUS_CODE = 13; + private static final byte MIN_STATUS_CODE_OPT_LEN = 6; + protected short mStatusCode; + + public static final short STATUS_SUCCESS = 0; + public static final short STATUS_UNSPEC_FAIL = 1; + public static final short STATUS_NO_ADDRS_AVAIL = 2; + public static final short STATUS_NO_BINDING = 3; + public static final short STATUS_NOT_ONLINK = 4; + public static final short STATUS_USE_MULTICAST = 5; + public static final short STATUS_NO_PREFIX_AVAIL = 6; + + /** + * DHCPv6 zero-length Optional Type: Rapid Commit. Per RFC4039, both DHCPDISCOVER and DHCPACK + * packet may include this option. + */ + public static final byte DHCP6_RAPID_COMMIT = 14; + public boolean mRapidCommit; + + /** + * DHCPv6 Optional Type: IA_PD. + */ + public static final byte DHCP6_IA_PD = 25; + @NonNull + protected final byte[] mIaPd; + @NonNull + protected PrefixDelegation mPrefixDelegation; + + /** + * DHCPv6 Optional Type: IA Prefix Option. + */ + public static final byte DHCP6_IAPREFIX = 26; + + /** + * DHCPv6 Optional Type: SOL_MAX_RT. + */ + public static final byte DHCP6_SOL_MAX_RT = 82; + private OptionalInt mSolMaxRt; + + /** + * The transaction identifier used in this particular DHCPv6 negotiation + */ + protected final int mTransId; + + /** + * The unique identifier for IA_NA, IA_TA, IA_PD used in this particular DHCPv6 negotiation + */ + protected int mIaId; + // Per rfc8415#section-12, the IAID MUST be consistent across restarts. + // Since currently only one IAID is supported, a well-known value can be used (0). + public static final int IAID = 0; + + Dhcp6Packet(int transId, int elapsedTime, @NonNull final byte[] clientDuid, + final byte[] serverDuid, @NonNull final byte[] iapd) { + mTransId = transId; + mElapsedTime = elapsedTime; + mClientDuid = clientDuid; + mServerDuid = serverDuid; + mIaPd = iapd; + } + + /** + * Returns the transaction ID. + */ + public int getTransactionId() { + return mTransId; + } + + /** + * Returns decoded IA_PD options associated with IA_ID. + */ + @VisibleForTesting + public PrefixDelegation getPrefixDelegation() { + return mPrefixDelegation; + } + + /** + * Returns IA_ID associated to IA_PD. + */ + public int getIaId() { + return mIaId; + } + + /** + * Returns the client's DUID. + */ + @NonNull + public byte[] getClientDuid() { + return mClientDuid; + } + + /** + * Returns the server's DUID. + */ + public byte[] getServerDuid() { + return mServerDuid; + } + + /** + * Returns the SOL_MAX_RT option value in milliseconds. + */ + public OptionalInt getSolMaxRtMs() { + return mSolMaxRt; + } + + /** + * A class to take DHCPv6 IA_PD option allocated from server. + * https://www.rfc-editor.org/rfc/rfc8415.html#section-21.21 + */ + public static class PrefixDelegation { + public final int iaid; + public final int t1; + public final int t2; + @NonNull + public final List ipos; + public final short statusCode; + + @VisibleForTesting + public PrefixDelegation(int iaid, int t1, int t2, + @NonNull final List ipos, short statusCode) { + Objects.requireNonNull(ipos); + this.iaid = iaid; + this.t1 = t1; + this.t2 = t2; + this.ipos = ipos; + this.statusCode = statusCode; + } + + public PrefixDelegation(int iaid, int t1, int t2, + @NonNull final List ipos) { + this(iaid, t1, t2, ipos, STATUS_SUCCESS /* statusCode */); + } + + /** + * Check whether or not the IA_PD option in DHCPv6 message is valid. + * + * TODO: ensure that the prefix has a reasonable lifetime, and the timers aren't too short. + */ + public boolean isValid() { + if (iaid != IAID) { + Log.w(TAG, "IA_ID doesn't match, expected: " + IAID + ", actual: " + iaid); + return false; + } + if (t1 < 0 || t2 < 0) { + Log.e(TAG, "IA_PD option with invalid T1 " + t1 + " or T2 " + t2); + return false; + } + // Generally, t1 must be smaller or equal to t2 (except when t2 is 0). + if (t2 != 0 && t1 > t2) { + Log.e(TAG, "IA_PD option with T1 " + t1 + " greater than T2 " + t2); + return false; + } + return true; + } + + /** + * Decode an IA_PD option from the byte buffer. + */ + public static PrefixDelegation decode(@NonNull final ByteBuffer buffer) + throws ParseException { + try { + final int iaid = buffer.getInt(); + final int t1 = buffer.getInt(); + final int t2 = buffer.getInt(); + final List ipos = new ArrayList(); + short statusCode = STATUS_SUCCESS; + while (buffer.remaining() > 0) { + final int original = buffer.position(); + final short optionType = buffer.getShort(); + final int optionLen = buffer.getShort() & 0xFFFF; + switch (optionType) { + case DHCP6_IAPREFIX: + buffer.position(original); + final IaPrefixOption ipo = Struct.parse(IaPrefixOption.class, buffer); + Log.d(TAG, "IA Prefix Option: " + ipo); + ipos.add(ipo); + break; + case DHCP6_STATUS_CODE: + statusCode = buffer.getShort(); + // Skip the status message if any. + if (optionLen > 2) { + skipOption(buffer, optionLen - 2); + } + break; + default: + skipOption(buffer, optionLen); + } + } + return new PrefixDelegation(iaid, t1, t2, ipos, statusCode); + } catch (BufferUnderflowException e) { + throw new ParseException(e.getMessage()); + } + } + + /** + * Build an IA_PD option from given specific parameters, including IA_PREFIX options. + */ + public ByteBuffer build() { + return build(ipos); + } + + /** + * Build an IA_PD option from given specific parameters, including IA_PREFIX options. + * + * Per RFC8415 section 21.13 if the Status Code option does not appear in a message in + * which the option could appear, the status of the message is assumed to be Success. So + * only put the Status Code option in IA_PD when the status code is not Success. + */ + public ByteBuffer build(@NonNull final List input) { + final ByteBuffer iapd = ByteBuffer.allocate(IaPdOption.LENGTH + + Struct.getSize(IaPrefixOption.class) * input.size() + + (statusCode != STATUS_SUCCESS ? MIN_STATUS_CODE_OPT_LEN : 0)); + iapd.putInt(iaid); + iapd.putInt(t1); + iapd.putInt(t2); + for (IaPrefixOption ipo : input) { + ipo.writeToByteBuffer(iapd); + } + if (statusCode != STATUS_SUCCESS) { + iapd.putShort(DHCP6_STATUS_CODE); + iapd.putShort((short) 2); + iapd.putShort(statusCode); + } + iapd.flip(); + return iapd; + } + + /** + * Return valid IA prefix options to be used and extended in the Reply message. It may + * return empty list if there isn't any valid IA prefix option in the Reply message. + * + * TODO: ensure that the prefix has a reasonable lifetime, and the timers aren't too short. + * and handle status code such as NoPrefixAvail. + */ + public List getValidIaPrefixes() { + final List validIpos = new ArrayList(); + for (IaPrefixOption ipo : ipos) { + if (!ipo.isValid()) continue; + validIpos.add(ipo); + } + return validIpos; + } + + @Override + public String toString() { + return String.format("Prefix Delegation, iaid: %s, t1: %s, t2: %s, status code: %s," + + " IA prefix options: %s", iaid, t1, t2, statusCodeToString(statusCode), ipos); + } + + /** + * Compare the preferred lifetime in the IA prefix optin list and return the minimum one. + */ + public long getMinimalPreferredLifetime() { + long min = Long.MAX_VALUE; + for (IaPrefixOption ipo : ipos) { + min = (ipo.preferred != 0 && min > ipo.preferred) ? ipo.preferred : min; + } + return min; + } + + /** + * Compare the valid lifetime in the IA prefix optin list and return the minimum one. + */ + public long getMinimalValidLifetime() { + long min = Long.MAX_VALUE; + for (IaPrefixOption ipo : ipos) { + min = (ipo.valid != 0 && min > ipo.valid) ? ipo.valid : min; + } + return min; + } + + /** + * Return IA prefix option list to be renewed/rebound. + * + * Per RFC8415#section-18.2.4, client must not include any prefixes that it didn't obtain + * from server or that are no longer valid (that have a valid lifetime of 0). Section-18.3.4 + * also mentions that server can inform client that it will not extend the prefix by setting + * T1 and T2 to values equal to the valid lifetime, so in this case client has no point in + * renewing as well. + */ + public List getRenewableIaPrefixes() { + final List toBeRenewed = getValidIaPrefixes(); + toBeRenewed.removeIf(ipo -> ipo.preferred == 0 && ipo.valid == 0); + toBeRenewed.removeIf(ipo -> t1 == ipo.valid && t2 == ipo.valid); + return toBeRenewed; + } + } + + /** + * DHCPv6 packet parsing exception. + */ + public static class ParseException extends Exception { + ParseException(String msg) { + super(msg); + } + } + + private static String statusCodeToString(short statusCode) { + switch (statusCode) { + case STATUS_SUCCESS: + return "Success"; + case STATUS_UNSPEC_FAIL: + return "UnspecFail"; + case STATUS_NO_ADDRS_AVAIL: + return "NoAddrsAvail"; + case STATUS_NO_BINDING: + return "NoBinding"; + case STATUS_NOT_ONLINK: + return "NotOnLink"; + case STATUS_USE_MULTICAST: + return "UseMulticast"; + case STATUS_NO_PREFIX_AVAIL: + return "NoPrefixAvail"; + default: + return "Unknown"; + } + } + + private static void skipOption(@NonNull final ByteBuffer packet, int optionLen) + throws BufferUnderflowException { + for (int i = 0; i < optionLen; i++) { + packet.get(); + } + } + + /** + * Creates a concrete Dhcp6Packet from the supplied ByteBuffer. + * + * The buffer only starts with a UDP encapsulation (i.e. DHCPv6 message). A subset of the + * optional parameters are parsed and are stored in object fields. Client/Server message + * format: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | msg-type | transaction-id | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * . options . + * . (variable number and length) . + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + private static Dhcp6Packet decode(@NonNull final ByteBuffer packet) throws ParseException { + int elapsedTime = 0; + byte[] iapd = null; + byte[] serverDuid = null; + byte[] clientDuid = null; + short statusCode = STATUS_SUCCESS; + boolean rapidCommit = false; + int solMaxRt = 0; + PrefixDelegation pd = null; + + packet.order(ByteOrder.BIG_ENDIAN); + + // DHCPv6 message contents. + final int msgTypeAndTransId = packet.getInt(); + final byte messageType = (byte) (msgTypeAndTransId >> 24); + final int transId = msgTypeAndTransId & 0xffffff; + + /** + * Parse DHCPv6 options, option format: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | option-code | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | option-data | + * | (option-len octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + while (packet.hasRemaining()) { + try { + final short optionType = packet.getShort(); + final int optionLen = packet.getShort() & 0xFFFF; + int expectedLen = 0; + + switch(optionType) { + case DHCP6_SERVER_IDENTIFIER: + expectedLen = optionLen; + final byte[] sduid = new byte[expectedLen]; + packet.get(sduid, 0 /* offset */, expectedLen); + serverDuid = sduid; + break; + case DHCP6_CLIENT_IDENTIFIER: + expectedLen = optionLen; + final byte[] cduid = new byte[expectedLen]; + packet.get(cduid, 0 /* offset */, expectedLen); + clientDuid = cduid; + break; + case DHCP6_IA_PD: + expectedLen = optionLen; + final byte[] bytes = new byte[expectedLen]; + packet.get(bytes, 0 /* offset */, expectedLen); + iapd = bytes; + pd = PrefixDelegation.decode(ByteBuffer.wrap(iapd)); + break; + case DHCP6_RAPID_COMMIT: + expectedLen = 0; + rapidCommit = true; + break; + case DHCP6_ELAPSED_TIME: + expectedLen = 2; + elapsedTime = (int) (packet.getShort() & 0xFFFF); + break; + case DHCP6_STATUS_CODE: + expectedLen = optionLen; + statusCode = packet.getShort(); + // Skip the status message (if any), which is a UTF-8 encoded text string + // suitable for display to the end user, but is not useful for Dhcp6Client + // to decide how to properly handle the status code. + if (optionLen - 2 > 0) { + skipOption(packet, optionLen - 2); + } + break; + case DHCP6_SOL_MAX_RT: + expectedLen = 4; + solMaxRt = packet.getInt(); + break; + default: + expectedLen = optionLen; + // BufferUnderflowException will be thrown if option is truncated. + skipOption(packet, optionLen); + break; + } + if (expectedLen != optionLen) { + throw new ParseException( + "Invalid length " + optionLen + " for option " + optionType + + ", expected " + expectedLen); + } + } catch (BufferUnderflowException e) { + throw new ParseException(e.getMessage()); + } + } + + Dhcp6Packet newPacket; + + switch(messageType) { + case DHCP6_MESSAGE_TYPE_SOLICIT: + newPacket = new Dhcp6SolicitPacket(transId, elapsedTime, clientDuid, iapd, + rapidCommit); + break; + case DHCP6_MESSAGE_TYPE_ADVERTISE: + newPacket = new Dhcp6AdvertisePacket(transId, clientDuid, serverDuid, iapd); + break; + case DHCP6_MESSAGE_TYPE_REQUEST: + newPacket = new Dhcp6RequestPacket(transId, elapsedTime, clientDuid, serverDuid, + iapd); + break; + case DHCP6_MESSAGE_TYPE_REPLY: + newPacket = new Dhcp6ReplyPacket(transId, clientDuid, serverDuid, iapd, + rapidCommit); + break; + case DHCP6_MESSAGE_TYPE_RENEW: + newPacket = new Dhcp6RenewPacket(transId, elapsedTime, clientDuid, serverDuid, + iapd); + break; + case DHCP6_MESSAGE_TYPE_REBIND: + newPacket = new Dhcp6RebindPacket(transId, elapsedTime, clientDuid, iapd); + break; + default: + throw new ParseException("Unimplemented DHCP6 message type %d" + messageType); + } + + if (pd != null) { + newPacket.mPrefixDelegation = pd; + newPacket.mIaId = pd.iaid; + } + newPacket.mStatusCode = statusCode; + newPacket.mRapidCommit = rapidCommit; + newPacket.mSolMaxRt = + (solMaxRt >= 60 && solMaxRt <= 86400) + ? OptionalInt.of(solMaxRt * 1000) + : OptionalInt.empty(); + + return newPacket; + } + + /** + * Parse a packet from an array of bytes, stopping at the given length. + */ + public static Dhcp6Packet decode(@NonNull final byte[] packet, int length) + throws ParseException { + final ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN); + return decode(buffer); + } + + /** + * Follow RFC8415 section 18.2.9 and 18.2.10 to check if the received DHCPv6 message is valid. + */ + public boolean isValid(int transId, @NonNull final byte[] clientDuid) { + if (mClientDuid == null) { + Log.e(TAG, "DHCPv6 message without Client DUID option"); + return false; + } + if (!Arrays.equals(mClientDuid, clientDuid)) { + Log.e(TAG, "Unexpected client DUID " + HexDump.toHexString(mClientDuid) + + ", expected " + HexDump.toHexString(clientDuid)); + return false; + } + if (mTransId != transId) { + Log.e(TAG, "Unexpected transaction ID " + mTransId + ", expected " + transId); + return false; + } + if (mPrefixDelegation == null) { + Log.e(TAG, "DHCPv6 message without IA_PD option, ignoring"); + return false; + } + if (!mPrefixDelegation.isValid()) { + Log.e(TAG, "DHCPv6 message takes invalid IA_PD option, ignoring"); + return false; + } + //TODO: check if the status code is success or not. + return true; + } + + /** + * Returns the client DUID, follows RFC 8415 and creates a client DUID + * based on the link-layer address(DUID-LL). + * + * TODO: use Struct to build and parse DUID. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | DUID-Type (3) | hardware type (16 bits) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . + * . link-layer address (variable length) . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + public static byte[] createClientDuid(@NonNull final MacAddress macAddress) { + final byte[] duid = new byte[10]; + // type: Link-layer address(3) + duid[0] = (byte) 0x00; + duid[1] = (byte) 0x03; + // hardware type: Ethernet(1) + duid[2] = (byte) 0x00; + duid[3] = (byte) 0x01; + System.arraycopy(macAddress.toByteArray() /* src */, 0 /* srcPos */, duid /* dest */, + 4 /* destPos */, 6 /* length */); + return duid; + } + + /** + * Adds an optional parameter containing an array of bytes. + */ + protected static void addTlv(ByteBuffer buf, short type, @NonNull byte[] payload) { + if (payload.length > DHCP_MAX_OPTION_LEN) { + throw new IllegalArgumentException("DHCP option too long: " + + payload.length + " vs. " + DHCP_MAX_OPTION_LEN); + } + buf.putShort(type); + buf.putShort((short) payload.length); + buf.put(payload); + } + + /** + * Adds an optional parameter containing a short integer. + */ + protected static void addTlv(ByteBuffer buf, short type, short value) { + buf.putShort(type); + buf.putShort((short) 2); + buf.putShort(value); + } + + /** + * Adds an optional parameter containing zero-length value. + */ + protected static void addTlv(ByteBuffer buf, short type) { + buf.putShort(type); + buf.putShort((short) 0); + } + + /** + * Builds a DHCPv6 SOLICIT packet from the required specified parameters. + */ + public static ByteBuffer buildSolicitPacket(int transId, long millisecs, + @NonNull final byte[] iapd, @NonNull final byte[] clientDuid, boolean rapidCommit) { + final Dhcp6SolicitPacket pkt = + new Dhcp6SolicitPacket(transId, (int) (millisecs / 10) /* elapsed time */, + clientDuid, iapd, rapidCommit); + return pkt.buildPacket(); + } + + /** + * Builds a DHCPv6 ADVERTISE packet from the required specified parameters. + */ + public static ByteBuffer buildAdvertisePacket(int transId, @NonNull final byte[] iapd, + @NonNull final byte[] clientDuid, @NonNull final byte[] serverDuid) { + final Dhcp6AdvertisePacket pkt = + new Dhcp6AdvertisePacket(transId, clientDuid, serverDuid, iapd); + return pkt.buildPacket(); + } + + /** + * Builds a DHCPv6 REPLY packet from the required specified parameters. + */ + public static ByteBuffer buildReplyPacket(int transId, @NonNull final byte[] iapd, + @NonNull final byte[] clientDuid, @NonNull final byte[] serverDuid, + boolean rapidCommit) { + final Dhcp6ReplyPacket pkt = + new Dhcp6ReplyPacket(transId, clientDuid, serverDuid, iapd, rapidCommit); + return pkt.buildPacket(); + } + + /** + * Builds a DHCPv6 REQUEST packet from the required specified parameters. + */ + public static ByteBuffer buildRequestPacket(int transId, long millisecs, + @NonNull final byte[] iapd, @NonNull final byte[] clientDuid, + @NonNull final byte[] serverDuid) { + final Dhcp6RequestPacket pkt = + new Dhcp6RequestPacket(transId, (int) (millisecs / 10) /* elapsed time */, + clientDuid, serverDuid, iapd); + return pkt.buildPacket(); + } + + /** + * Builds a DHCPv6 RENEW packet from the required specified parameters. + */ + public static ByteBuffer buildRenewPacket(int transId, long millisecs, + @NonNull final byte[] iapd, @NonNull final byte[] clientDuid, + @NonNull final byte[] serverDuid) { + final Dhcp6RenewPacket pkt = + new Dhcp6RenewPacket(transId, (int) (millisecs / 10) /* elapsed time */, clientDuid, + serverDuid, iapd); + return pkt.buildPacket(); + } + + /** + * Builds a DHCPv6 REBIND packet from the required specified parameters. + */ + public static ByteBuffer buildRebindPacket(int transId, long millisecs, + @NonNull final byte[] iapd, @NonNull final byte[] clientDuid) { + final Dhcp6RebindPacket pkt = new Dhcp6RebindPacket(transId, + (int) (millisecs / 10) /* elapsed time */, clientDuid, iapd); + return pkt.buildPacket(); + } +} diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RebindPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RebindPacket.java new file mode 100644 index 0000000000..87f2f45b0a --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RebindPacket.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 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.dhcp6; + +import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; + +import androidx.annotation.NonNull; + +import java.nio.ByteBuffer; + +/** + * DHCPv6 REBIND packet class, a client sends a Rebind message to any available server to extend + * the lifetimes on the leases assigned to the client and to update other configuration parameters. + * This message is sent after a client receives no response to a Renew message. + * + * https://tools.ietf.org/html/rfc8415#page-24 + */ +public class Dhcp6RebindPacket extends Dhcp6Packet { + /** + * Generates a rebind packet with the specified parameters. + */ + Dhcp6RebindPacket(int transId, int elapsedTime, @NonNull final byte[] clientDuid, + @NonNull final byte[] iapd) { + super(transId, elapsedTime, clientDuid, null /* serverDuid */, iapd); + } + + /** + * Build a DHCPv6 Rebind message with the specific parameters. + */ + public ByteBuffer buildPacket() { + final ByteBuffer packet = ByteBuffer.allocate(DHCP_MAX_LENGTH); + final int msgTypeAndTransId = (DHCP6_MESSAGE_TYPE_REBIND << 24) | mTransId; + packet.putInt(msgTypeAndTransId); + + addTlv(packet, DHCP6_CLIENT_IDENTIFIER, getClientDuid()); + addTlv(packet, DHCP6_ELAPSED_TIME, (short) (mElapsedTime & 0xFFFF)); + addTlv(packet, DHCP6_IA_PD, mIaPd); + + packet.flip(); + return packet; + } +} diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RenewPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RenewPacket.java new file mode 100644 index 0000000000..8c6686c7f6 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RenewPacket.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 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.dhcp6; + +import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; + +import androidx.annotation.NonNull; + +import java.nio.ByteBuffer; + +/** + * DHCPv6 RENEW packet class, a client sends an Renew message to the server that originally + * provided the client's leases and configuration parameters to extend the lifetimes on the + * leases assigned to the client and to update other configuration parameters. + * + * https://tools.ietf.org/html/rfc8415#page-24 + */ +public class Dhcp6RenewPacket extends Dhcp6Packet { + /** + * Generates a renew packet with the specified parameters. + */ + Dhcp6RenewPacket(int transId, int elapsedTime, @NonNull final byte[] clientDuid, + @NonNull final byte[] serverDuid, final byte[] iapd) { + super(transId, elapsedTime, clientDuid, serverDuid, iapd); + } + + /** + * Build a DHCPv6 Renew message with the specific parameters. + */ + public ByteBuffer buildPacket() { + final ByteBuffer packet = ByteBuffer.allocate(DHCP_MAX_LENGTH); + final int msgTypeAndTransId = (DHCP6_MESSAGE_TYPE_RENEW << 24) | mTransId; + packet.putInt(msgTypeAndTransId); + + addTlv(packet, DHCP6_SERVER_IDENTIFIER, mServerDuid); + addTlv(packet, DHCP6_CLIENT_IDENTIFIER, mClientDuid); + addTlv(packet, DHCP6_ELAPSED_TIME, (short) (mElapsedTime & 0xFFFF)); + addTlv(packet, DHCP6_IA_PD, mIaPd); + + packet.flip(); + return packet; + } +} diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6ReplyPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6ReplyPacket.java new file mode 100644 index 0000000000..d68fbdb733 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6ReplyPacket.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 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.dhcp6; + +import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; + +import androidx.annotation.NonNull; + +import java.nio.ByteBuffer; + +/** + * DHCPv6 REPLY packet class, a server sends an Reply message containing assigned leases + * and configuration parameters in response to a Solicit, Request, Renew or Rebind messages + * received from a client. + * + * https://tools.ietf.org/html/rfc8415#page-24 + */ +public class Dhcp6ReplyPacket extends Dhcp6Packet { + /** + * Generates a reply packet with the specified parameters. + */ + Dhcp6ReplyPacket(int transId, @NonNull final byte[] clientDuid, + @NonNull final byte[] serverDuid, final byte[] iapd, boolean rapidCommit) { + super(transId, 0 /* elapsedTime */, clientDuid, serverDuid, iapd); + mRapidCommit = rapidCommit; + } + + /** + * Build a DHCPv6 Reply message with the specific parameters. + */ + public ByteBuffer buildPacket() { + final ByteBuffer packet = ByteBuffer.allocate(DHCP_MAX_LENGTH); + final int msgTypeAndTransId = (DHCP6_MESSAGE_TYPE_REPLY << 24) | mTransId; + packet.putInt(msgTypeAndTransId); + + addTlv(packet, DHCP6_CLIENT_IDENTIFIER, mClientDuid); + addTlv(packet, DHCP6_SERVER_IDENTIFIER, mServerDuid); + addTlv(packet, DHCP6_IA_PD, mIaPd); + if (mRapidCommit) { + addTlv(packet, DHCP6_RAPID_COMMIT); + } + + packet.flip(); + return packet; + } +} diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RequestPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RequestPacket.java new file mode 100644 index 0000000000..6d4dfdf1d9 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RequestPacket.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 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.dhcp6; + +import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; + +import androidx.annotation.NonNull; + +import java.nio.ByteBuffer; + +/** + * DHCPv6 REQUEST packet class, a client sends a Request message to request configuration + * parameters, including addresses and/or delegated prefixes from a specific server. + * + * https://tools.ietf.org/html/rfc8415#page-24 + */ +public class Dhcp6RequestPacket extends Dhcp6Packet { + /** + * Generates a request packet with the specified parameters. + */ + Dhcp6RequestPacket(int transId, int elapsedTime, @NonNull final byte[] clientDuid, + @NonNull final byte[] serverDuid, final byte[] iapd) { + super(transId, elapsedTime, clientDuid, serverDuid, iapd); + } + + /** + * Build a DHCPv6 Request message with the specific parameters. + */ + public ByteBuffer buildPacket() { + final ByteBuffer packet = ByteBuffer.allocate(DHCP_MAX_LENGTH); + final int msgTypeAndTransId = (DHCP6_MESSAGE_TYPE_REQUEST << 24) | mTransId; + packet.putInt(msgTypeAndTransId); + + addTlv(packet, DHCP6_SERVER_IDENTIFIER, mServerDuid); + addTlv(packet, DHCP6_CLIENT_IDENTIFIER, mClientDuid); + addTlv(packet, DHCP6_ELAPSED_TIME, (short) (mElapsedTime & 0xFFFF)); + addTlv(packet, DHCP6_IA_PD, mIaPd); + addTlv(packet, DHCP6_OPTION_REQUEST_OPTION, DHCP6_SOL_MAX_RT); + + packet.flip(); + return packet; + } +} diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6SolicitPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6SolicitPacket.java new file mode 100644 index 0000000000..5cf5d01375 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6SolicitPacket.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 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.dhcp6; + +import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; + +import androidx.annotation.NonNull; + +import java.nio.ByteBuffer; + +/** + * DHCPv6 SOLICIT packet class, a client sends a Solicit message to locate DHCPv6 servers. + * + * https://tools.ietf.org/html/rfc8415#page-24 + */ +public class Dhcp6SolicitPacket extends Dhcp6Packet { + /** + * Generates a solicit packet with the specified parameters. + */ + Dhcp6SolicitPacket(int transId, int elapsedTime, @NonNull final byte[] clientDuid, + final byte[] iapd, boolean rapidCommit) { + super(transId, elapsedTime, clientDuid, null /* serverDuid */, iapd); + mRapidCommit = rapidCommit; + } + + /** + * Build a DHCPv6 Solicit message with the specific parameters. + */ + public ByteBuffer buildPacket() { + final ByteBuffer packet = ByteBuffer.allocate(DHCP_MAX_LENGTH); + final int msgTypeAndTransId = (DHCP6_MESSAGE_TYPE_SOLICIT << 24) | mTransId; + packet.putInt(msgTypeAndTransId); + + addTlv(packet, DHCP6_ELAPSED_TIME, (short) (mElapsedTime & 0xFFFF)); + addTlv(packet, DHCP6_CLIENT_IDENTIFIER, mClientDuid); + addTlv(packet, DHCP6_IA_PD, mIaPd); + addTlv(packet, DHCP6_OPTION_REQUEST_OPTION, DHCP6_SOL_MAX_RT); + if (mRapidCommit) { + addTlv(packet, DHCP6_RAPID_COMMIT); + } + + packet.flip(); + return packet; + } +} From f5e80bfb70ad50b0b91101be927ba9262541674f Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 1 May 2025 10:47:02 -0700 Subject: [PATCH 2/3] Add Dhcp6*Packet classes to net-utils-networkstack Test: TH Flag: EXEMPT mainline Bug: 1000001 Change-Id: Ica554c27a648095a23331a9d93cc6bbbcf572cec --- staticlibs/Android.bp | 3 +++ .../net/module/util/dhcp6/Dhcp6AdvertisePacket.java | 4 +--- .../com/android/net/module/util/dhcp6/Dhcp6Packet.java | 10 ++++++---- .../net/module/util/dhcp6/Dhcp6RebindPacket.java | 4 +--- .../net/module/util/dhcp6/Dhcp6RenewPacket.java | 4 +--- .../net/module/util/dhcp6/Dhcp6ReplyPacket.java | 4 +--- .../net/module/util/dhcp6/Dhcp6RequestPacket.java | 4 +--- .../net/module/util/dhcp6/Dhcp6SolicitPacket.java | 4 +--- 8 files changed, 15 insertions(+), 22 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 5e01efaa96..00f2f9b338 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -86,6 +86,7 @@ java_library { name: "net-utils-networkstack", srcs: [ "device/com/android/net/module/util/ProcfsParsingUtils.java", + "device/com/android/net/module/util/dhcp6/*.java", "framework/com/android/net/module/util/HexDump.java", ], sdk_version: "module_current", @@ -99,6 +100,8 @@ java_library { "androidx.annotation_annotation", "framework-annotations-lib", "framework-connectivity.stubs.module_lib", + "net-utils-device-common-struct", + "net-utils-device-common-struct-base", ], } diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6AdvertisePacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6AdvertisePacket.java index 263ab5ff04..57dfb07c3c 100644 --- a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6AdvertisePacket.java +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6AdvertisePacket.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package android.net.dhcp6; - -import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; +package com.android.net.module.util.dhcp6; import androidx.annotation.NonNull; diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java index ff7b036d61..29c25556ff 100644 --- a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package android.net.dhcp6; - -import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_OPTION_LEN; +package com.android.net.module.util.dhcp6; import android.net.MacAddress; import android.util.Log; @@ -24,7 +22,7 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.HexDump; +import com.android.net.module.util.HexDump; import com.android.net.module.util.Struct; import com.android.net.module.util.structs.IaPdOption; import com.android.net.module.util.structs.IaPrefixOption; @@ -47,6 +45,10 @@ import java.util.OptionalInt; */ public class Dhcp6Packet { private static final String TAG = Dhcp6Packet.class.getSimpleName(); + /** DHCP constants copied from NetworkStackConstants.java */ + protected static final int DHCP_MAX_LENGTH = 1500; + protected static final int DHCP_MAX_OPTION_LEN = 255; + /** * DHCPv6 Message Type. */ diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RebindPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RebindPacket.java index 87f2f45b0a..5f795fe37a 100644 --- a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RebindPacket.java +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RebindPacket.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package android.net.dhcp6; - -import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; +package com.android.net.module.util.dhcp6; import androidx.annotation.NonNull; diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RenewPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RenewPacket.java index 8c6686c7f6..7dc7267959 100644 --- a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RenewPacket.java +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RenewPacket.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package android.net.dhcp6; - -import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; +package com.android.net.module.util.dhcp6; import androidx.annotation.NonNull; diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6ReplyPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6ReplyPacket.java index d68fbdb733..74ccee2a60 100644 --- a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6ReplyPacket.java +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6ReplyPacket.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package android.net.dhcp6; - -import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; +package com.android.net.module.util.dhcp6; import androidx.annotation.NonNull; diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RequestPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RequestPacket.java index 6d4dfdf1d9..cfb16437db 100644 --- a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RequestPacket.java +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6RequestPacket.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package android.net.dhcp6; - -import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; +package com.android.net.module.util.dhcp6; import androidx.annotation.NonNull; diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6SolicitPacket.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6SolicitPacket.java index 5cf5d01375..ff86052f64 100644 --- a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6SolicitPacket.java +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6SolicitPacket.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package android.net.dhcp6; - -import static com.android.net.module.util.NetworkStackConstants.DHCP_MAX_LENGTH; +package com.android.net.module.util.dhcp6; import androidx.annotation.NonNull; From a2a1295adca24082525a06042ee63d05a66f3ad7 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 1 May 2025 11:11:40 -0700 Subject: [PATCH 3/3] Expose a getter for mStatusCode So it is accessible by the test. Test: TH Flag: EXEMPT mainline Bug: 1000001 Change-Id: Ibc30ede2e6a21e33ad3b4d7f21d03aba54a121ba --- .../com/android/net/module/util/dhcp6/Dhcp6Packet.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java index 29c25556ff..559e8319f9 100644 --- a/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java +++ b/staticlibs/device/com/android/net/module/util/dhcp6/Dhcp6Packet.java @@ -200,6 +200,11 @@ public class Dhcp6Packet { return mSolMaxRt; } + /** Returns the OPTION_STATUS_CODE value as defined in rfc8415#section-21.13 */ + public Short getStatusCode() { + return mStatusCode; + } + /** * A class to take DHCPv6 IA_PD option allocated from server. * https://www.rfc-editor.org/rfc/rfc8415.html#section-21.21