diff options
author | Remi NGUYEN VAN <reminv@google.com> | 2020-11-10 15:29:01 +0900 |
---|---|---|
committer | Remi NGUYEN VAN <reminv@google.com> | 2020-12-14 18:43:44 +0900 |
commit | 103ec4aa8d2c9c573840346e18ea9a20a5adc356 (patch) | |
tree | b4504c07c624c8c7dc40d9a85909c97f649c17d3 /services/net/java | |
parent | 294dd8f1da16d03367e4af6f9fbf120e4d8674d5 (diff) |
Add TcpKeepalivePacketData to SystemApi
This is consistent with NattKeepalivePacketData, which is also a
subclass of KeepalivePacketData.
TcpKeepalivePacketData is already used by the wifi module, but
statically linked.
Bug: 172789687
Test: m
Change-Id: I6aee1ae205987521bea4a3838bbece279ffa0e37
Diffstat (limited to 'services/net/java')
3 files changed, 129 insertions, 273 deletions
diff --git a/services/net/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java deleted file mode 100644 index 4875c7cc4263..000000000000 --- a/services/net/java/android/net/TcpKeepalivePacketData.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2019 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; - -import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.system.OsConstants; - -import com.android.net.module.util.IpUtils; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * Represents the actual tcp keep alive packets which will be used for hardware offload. - * @hide - */ -public class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable { - private static final String TAG = "TcpKeepalivePacketData"; - - /** TCP sequence number. */ - public final int tcpSeq; - - /** TCP ACK number. */ - public final int tcpAck; - - /** TCP RCV window. */ - public final int tcpWnd; - - /** TCP RCV window scale. */ - public final int tcpWndScale; - - /** IP TOS. */ - public final int ipTos; - - /** IP TTL. */ - public final int ipTtl; - - private static final int IPV4_HEADER_LENGTH = 20; - private static final int IPV6_HEADER_LENGTH = 40; - private static final int TCP_HEADER_LENGTH = 20; - - // This should only be constructed via static factory methods, such as - // tcpKeepalivePacket. - private TcpKeepalivePacketData(final TcpKeepalivePacketDataParcelable tcpDetails, - final byte[] data) throws InvalidPacketException, UnknownHostException { - super(InetAddress.getByAddress(tcpDetails.srcAddress), tcpDetails.srcPort, - InetAddress.getByAddress(tcpDetails.dstAddress), tcpDetails.dstPort, data); - tcpSeq = tcpDetails.seq; - tcpAck = tcpDetails.ack; - // In the packet, the window is shifted right by the window scale. - tcpWnd = tcpDetails.rcvWnd; - tcpWndScale = tcpDetails.rcvWndScale; - ipTos = tcpDetails.tos; - ipTtl = tcpDetails.ttl; - } - - private TcpKeepalivePacketData(final InetAddress srcAddress, int srcPort, - final InetAddress dstAddress, int dstPort, final byte[] data, int tcpSeq, - int tcpAck, int tcpWnd, int tcpWndScale, int ipTos, int ipTtl) - throws InvalidPacketException { - super(srcAddress, srcPort, dstAddress, dstPort, data); - this.tcpSeq = tcpSeq; - this.tcpAck = tcpAck; - this.tcpWnd = tcpWnd; - this.tcpWndScale = tcpWndScale; - this.ipTos = ipTos; - this.ipTtl = ipTtl; - } - - /** - * Factory method to create tcp keepalive packet structure. - */ - public static TcpKeepalivePacketData tcpKeepalivePacket( - TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException { - final byte[] packet; - try { - if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null) - && (tcpDetails.srcAddress.length == 4 /* V4 IP length */) - && (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) { - packet = buildV4Packet(tcpDetails); - } else { - // TODO: support ipv6 - throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); - } - return new TcpKeepalivePacketData(tcpDetails, packet); - } catch (UnknownHostException e) { - throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); - } - - } - - /** - * Build ipv4 tcp keepalive packet, not including the link-layer header. - */ - // TODO : if this code is ever moved to the network stack, factorize constants with the ones - // over there. - private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) { - final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH; - ByteBuffer buf = ByteBuffer.allocate(length); - buf.order(ByteOrder.BIG_ENDIAN); - buf.put((byte) 0x45); // IP version and IHL - buf.put((byte) tcpDetails.tos); // TOS - buf.putShort((short) length); - buf.putInt(0x00004000); // ID, flags=DF, offset - buf.put((byte) tcpDetails.ttl); // TTL - buf.put((byte) OsConstants.IPPROTO_TCP); - final int ipChecksumOffset = buf.position(); - buf.putShort((short) 0); // IP checksum - buf.put(tcpDetails.srcAddress); - buf.put(tcpDetails.dstAddress); - buf.putShort((short) tcpDetails.srcPort); - buf.putShort((short) tcpDetails.dstPort); - buf.putInt(tcpDetails.seq); // Sequence Number - buf.putInt(tcpDetails.ack); // ACK - buf.putShort((short) 0x5010); // TCP length=5, flags=ACK - buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size - final int tcpChecksumOffset = buf.position(); - buf.putShort((short) 0); // TCP checksum - // URG is not set therefore the urgent pointer is zero. - buf.putShort((short) 0); // Urgent pointer - - buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); - buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum( - buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH)); - - return buf.array(); - } - - // TODO: add buildV6Packet. - - @Override - public boolean equals(@Nullable final Object o) { - if (!(o instanceof TcpKeepalivePacketData)) return false; - final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o; - final InetAddress srcAddress = getSrcAddress(); - final InetAddress dstAddress = getDstAddress(); - return srcAddress.equals(other.getSrcAddress()) - && dstAddress.equals(other.getDstAddress()) - && getSrcPort() == other.getSrcPort() - && getDstPort() == other.getDstPort() - && this.tcpAck == other.tcpAck - && this.tcpSeq == other.tcpSeq - && this.tcpWnd == other.tcpWnd - && this.tcpWndScale == other.tcpWndScale - && this.ipTos == other.ipTos - && this.ipTtl == other.ipTtl; - } - - @Override - public int hashCode() { - return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort(), - tcpAck, tcpSeq, tcpWnd, tcpWndScale, ipTos, ipTtl); - } - - /** - * Parcelable Implementation. - * Note that this object implements parcelable (and needs to keep doing this as it inherits - * from a class that does), but should usually be parceled as a stable parcelable using - * the toStableParcelable() and fromStableParcelable() methods. - */ - public int describeContents() { - return 0; - } - - /** Write to parcel. */ - public void writeToParcel(Parcel out, int flags) { - out.writeString(getSrcAddress().getHostAddress()); - out.writeString(getDstAddress().getHostAddress()); - out.writeInt(getSrcPort()); - out.writeInt(getDstPort()); - out.writeByteArray(getPacket()); - out.writeInt(tcpSeq); - out.writeInt(tcpAck); - out.writeInt(tcpWnd); - out.writeInt(tcpWndScale); - out.writeInt(ipTos); - out.writeInt(ipTtl); - } - - private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException { - InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString()); - InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString()); - int srcPort = in.readInt(); - int dstPort = in.readInt(); - byte[] packet = in.createByteArray(); - int tcpSeq = in.readInt(); - int tcpAck = in.readInt(); - int tcpWnd = in.readInt(); - int tcpWndScale = in.readInt(); - int ipTos = in.readInt(); - int ipTtl = in.readInt(); - return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq, - tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl); - } - - /** Parcelable Creator. */ - public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR = - new Parcelable.Creator<TcpKeepalivePacketData>() { - public TcpKeepalivePacketData createFromParcel(Parcel in) { - try { - return readFromParcel(in); - } catch (InvalidPacketException e) { - throw new IllegalArgumentException( - "Invalid NAT-T keepalive data: " + e.getError()); - } - } - - public TcpKeepalivePacketData[] newArray(int size) { - return new TcpKeepalivePacketData[size]; - } - }; - - /** - * Convert this TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable. - */ - @NonNull - public TcpKeepalivePacketDataParcelable toStableParcelable() { - final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable(); - final InetAddress srcAddress = getSrcAddress(); - final InetAddress dstAddress = getDstAddress(); - parcel.srcAddress = srcAddress.getAddress(); - parcel.srcPort = getSrcPort(); - parcel.dstAddress = dstAddress.getAddress(); - parcel.dstPort = getDstPort(); - parcel.seq = tcpSeq; - parcel.ack = tcpAck; - parcel.rcvWnd = tcpWnd; - parcel.rcvWndScale = tcpWndScale; - parcel.tos = ipTos; - parcel.ttl = ipTtl; - return parcel; - } - - @Override - public String toString() { - return "saddr: " + getSrcAddress() - + " daddr: " + getDstAddress() - + " sport: " + getSrcPort() - + " dport: " + getDstPort() - + " seq: " + tcpSeq - + " ack: " + tcpAck - + " wnd: " + tcpWnd - + " wndScale: " + tcpWndScale - + " tos: " + ipTos - + " ttl: " + ipTtl; - } -} diff --git a/services/net/java/android/net/ip/IpClientManager.java b/services/net/java/android/net/ip/IpClientManager.java index db464e732e91..274b6dc1769b 100644 --- a/services/net/java/android/net/ip/IpClientManager.java +++ b/services/net/java/android/net/ip/IpClientManager.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.net.NattKeepalivePacketData; import android.net.ProxyInfo; import android.net.TcpKeepalivePacketData; +import android.net.TcpKeepalivePacketDataParcelable; import android.net.shared.Layer2Information; import android.net.shared.ProvisioningConfiguration; import android.net.util.KeepalivePacketDataUtil; @@ -215,9 +216,20 @@ public class IpClientManager { * Add a TCP keepalive packet filter before setting up keepalive offload. */ public boolean addKeepalivePacketFilter(int slot, TcpKeepalivePacketData pkt) { + return addKeepalivePacketFilter(slot, KeepalivePacketDataUtil.toStableParcelable(pkt)); + } + + /** + * Add a TCP keepalive packet filter before setting up keepalive offload. + * @deprecated This method is for use on pre-S platforms where TcpKeepalivePacketData is not + * system API. On newer platforms use + * addKeepalivePacketFilter(int, TcpKeepalivePacketData) instead. + */ + @Deprecated + public boolean addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) { final long token = Binder.clearCallingIdentity(); try { - mIpClient.addKeepalivePacketFilter(slot, pkt.toStableParcelable()); + mIpClient.addKeepalivePacketFilter(slot, pkt); return true; } catch (RemoteException e) { log("Error adding Keepalive Packet Filter ", e); diff --git a/services/net/java/android/net/util/KeepalivePacketDataUtil.java b/services/net/java/android/net/util/KeepalivePacketDataUtil.java index 4466ea0abe0e..f06070b6870d 100644 --- a/services/net/java/android/net/util/KeepalivePacketDataUtil.java +++ b/services/net/java/android/net/util/KeepalivePacketDataUtil.java @@ -16,20 +16,41 @@ package android.net.util; +import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; + import android.annotation.NonNull; +import android.net.InvalidPacketException; import android.net.NattKeepalivePacketData; import android.net.NattKeepalivePacketDataParcelable; +import android.net.TcpKeepalivePacketData; +import android.net.TcpKeepalivePacketDataParcelable; +import android.system.OsConstants; + +import com.android.net.module.util.IpUtils; import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; -/** @hide */ +/** + * Utility class to convert to/from keepalive data parcelables. + * + * TODO: move to networkstack-client library when it is moved to frameworks/libs/net. + * This class cannot go into other shared libraries as it depends on NetworkStack AIDLs. + * @hide + */ public final class KeepalivePacketDataUtil { - /** - * Convert this NattKeepalivePacketData to a NattKeepalivePacketDataParcelable. + private static final int IPV4_HEADER_LENGTH = 20; + private static final int IPV6_HEADER_LENGTH = 40; + private static final int TCP_HEADER_LENGTH = 20; + + /** + * Convert a NattKeepalivePacketData to a NattKeepalivePacketDataParcelable. */ @NonNull public static NattKeepalivePacketDataParcelable toStableParcelable( - NattKeepalivePacketData pkt) { + @NonNull NattKeepalivePacketData pkt) { final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable(); final InetAddress srcAddress = pkt.getSrcAddress(); final InetAddress dstAddress = pkt.getDstAddress(); @@ -39,4 +60,95 @@ public final class KeepalivePacketDataUtil { parcel.dstPort = pkt.getDstPort(); return parcel; } + + /** + * Convert a TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable. + */ + @NonNull + public static TcpKeepalivePacketDataParcelable toStableParcelable( + @NonNull TcpKeepalivePacketData pkt) { + final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable(); + final InetAddress srcAddress = pkt.getSrcAddress(); + final InetAddress dstAddress = pkt.getDstAddress(); + parcel.srcAddress = srcAddress.getAddress(); + parcel.srcPort = pkt.getSrcPort(); + parcel.dstAddress = dstAddress.getAddress(); + parcel.dstPort = pkt.getDstPort(); + parcel.seq = pkt.tcpSeq; + parcel.ack = pkt.tcpAck; + parcel.rcvWnd = pkt.tcpWindow; + parcel.rcvWndScale = pkt.tcpWindowScale; + parcel.tos = pkt.ipTos; + parcel.ttl = pkt.ipTtl; + return parcel; + } + + /** + * Factory method to create tcp keepalive packet structure. + * @hide + */ + public static TcpKeepalivePacketData fromStableParcelable( + TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException { + final byte[] packet; + try { + if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null) + && (tcpDetails.srcAddress.length == 4 /* V4 IP length */) + && (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) { + packet = buildV4Packet(tcpDetails); + } else { + // TODO: support ipv6 + throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); + } + return new TcpKeepalivePacketData( + InetAddress.getByAddress(tcpDetails.srcAddress), + tcpDetails.srcPort, + InetAddress.getByAddress(tcpDetails.dstAddress), + tcpDetails.dstPort, + packet, + tcpDetails.seq, tcpDetails.ack, tcpDetails.rcvWnd, tcpDetails.rcvWndScale, + tcpDetails.tos, tcpDetails.ttl); + } catch (UnknownHostException e) { + throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); + } + + } + + /** + * Build ipv4 tcp keepalive packet, not including the link-layer header. + */ + // TODO : if this code is ever moved to the network stack, factorize constants with the ones + // over there. + private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) { + final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH; + ByteBuffer buf = ByteBuffer.allocate(length); + buf.order(ByteOrder.BIG_ENDIAN); + buf.put((byte) 0x45); // IP version and IHL + buf.put((byte) tcpDetails.tos); // TOS + buf.putShort((short) length); + buf.putInt(0x00004000); // ID, flags=DF, offset + buf.put((byte) tcpDetails.ttl); // TTL + buf.put((byte) OsConstants.IPPROTO_TCP); + final int ipChecksumOffset = buf.position(); + buf.putShort((short) 0); // IP checksum + buf.put(tcpDetails.srcAddress); + buf.put(tcpDetails.dstAddress); + buf.putShort((short) tcpDetails.srcPort); + buf.putShort((short) tcpDetails.dstPort); + buf.putInt(tcpDetails.seq); // Sequence Number + buf.putInt(tcpDetails.ack); // ACK + buf.putShort((short) 0x5010); // TCP length=5, flags=ACK + buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size + final int tcpChecksumOffset = buf.position(); + buf.putShort((short) 0); // TCP checksum + // URG is not set therefore the urgent pointer is zero. + buf.putShort((short) 0); // Urgent pointer + + buf.putShort(ipChecksumOffset, com.android.net.module.util.IpUtils.ipChecksum(buf, 0)); + buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum( + buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH)); + + return buf.array(); + } + + // TODO: add buildV6Packet. } |