blob: 5c3e40a9e9ba44b74dac44a1806e75077841fe86 [file] [log] [blame]
/*
* Copyright (C) 2021 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 com.android.networkstack.packets;
import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NS_HEADER_LEN;
import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
import android.net.MacAddress;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.net.module.util.Ipv6Utils;
import com.android.net.module.util.Struct;
import com.android.net.module.util.structs.EthernetHeader;
import com.android.net.module.util.structs.Icmpv6Header;
import com.android.net.module.util.structs.Ipv6Header;
import com.android.net.module.util.structs.LlaOption;
import com.android.net.module.util.structs.NsHeader;
import java.net.Inet6Address;
import java.nio.ByteBuffer;
/**
* Defines basic data and operations needed to build and parse Neighbor Solicitation packet.
*
* @hide
*/
public class NeighborSolicitation {
@NonNull
public final EthernetHeader ethHdr;
@NonNull
public final Ipv6Header ipv6Hdr;
@NonNull
public final Icmpv6Header icmpv6Hdr;
@NonNull
public final NsHeader nsHdr;
@Nullable
public final LlaOption slla;
public NeighborSolicitation(@NonNull final EthernetHeader ethHdr,
@NonNull final Ipv6Header ipv6Hdr, @NonNull final Icmpv6Header icmpv6Hdr,
@NonNull final NsHeader nsHdr, @Nullable final LlaOption slla) {
this.ethHdr = ethHdr;
this.ipv6Hdr = ipv6Hdr;
this.icmpv6Hdr = icmpv6Hdr;
this.nsHdr = nsHdr;
this.slla = slla;
}
/**
* Convert a Neighbor Solicitation instance to ByteBuffer.
*/
public ByteBuffer toByteBuffer() {
final int etherHeaderLen = Struct.getSize(EthernetHeader.class);
final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class);
final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class);
final int nsHeaderLen = Struct.getSize(NsHeader.class);
final int sllaOptionLen = (slla == null) ? 0 : Struct.getSize(LlaOption.class);
final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen
+ icmpv6HeaderLen + nsHeaderLen + sllaOptionLen);
ethHdr.writeToByteBuffer(packet);
ipv6Hdr.writeToByteBuffer(packet);
icmpv6Hdr.writeToByteBuffer(packet);
nsHdr.writeToByteBuffer(packet);
if (slla != null) {
slla.writeToByteBuffer(packet);
}
packet.flip();
return packet;
}
/**
* Build a Neighbor Solicitation packet from the required specified parameters.
*/
public static ByteBuffer build(@NonNull final MacAddress srcMac,
@NonNull final MacAddress dstMac, @NonNull final Inet6Address srcIp,
@NonNull final Inet6Address dstIp, @NonNull final Inet6Address target) {
final ByteBuffer slla = LlaOption.build((byte) ICMPV6_ND_OPTION_SLLA, srcMac);
return Ipv6Utils.buildNsPacket(srcMac, dstMac, srcIp, dstIp, target, slla);
}
/**
* Parse a Neighbor Solicitation packet from ByteBuffer.
*/
public static NeighborSolicitation parse(@NonNull final byte[] recvbuf, final int length)
throws ParseException {
if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_NS_HEADER_LEN
|| recvbuf.length < length) {
throw new ParseException("Invalid packet length: " + length);
}
final ByteBuffer packet = ByteBuffer.wrap(recvbuf, 0, length);
// Parse each header and option in Neighbor Solicitation packet in order.
final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, packet);
final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, packet);
final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, packet);
final NsHeader nsHdr = Struct.parse(NsHeader.class, packet);
final LlaOption slla = (packet.remaining() == 0)
? null
: Struct.parse(LlaOption.class, packet);
return new NeighborSolicitation(ethHdr, ipv6Hdr, icmpv6Hdr, nsHdr, slla);
}
/**
* Thrown when parsing Neighbor Solicitation packet failed.
*/
public static class ParseException extends Exception {
ParseException(String message) {
super(message);
}
}
}