class Ipv6Decoder extends AbstractPacketDecoder<EthernetPacketReceived, Ipv6PacketReceived> implements EthernetPacketListener {

    @Override
    public Ipv6PacketReceived decode(EthernetPacketReceived ethernetPacketReceived) {
        Ipv6PacketReceivedBuilder ipv6ReceivedBuilder = new Ipv6PacketReceivedBuilder();

        // Find the latest packet in the packet-chain, which is an
        // EthernetPacket
        List<PacketChain> packetChainList = ethernetPacketReceived.getPacketChain();
        EthernetPacket ethernetPacket = (EthernetPacket) packetChainList.get(packetChainList.size() - 1).getPacket();
        int bitOffset = ethernetPacket.getPayloadOffset() * NetUtils.NUM_BITS_IN_A_BYTE;
        byte[] data = ethernetPacketReceived.getPayload();

        Ipv6PacketBuilder builder = new Ipv6PacketBuilder();
        try {
            builder.setVersion(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 4)));
            if (builder.getVersion().intValue() != 6) {
                LOG.debug("Version should be 6, but is {}", builder.getVersion());
            }

            builder.setDscp(new Dscp(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 4, 6))));
            builder.setEcn(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 10, 2)));
            builder.setFlowLabel(BitBufferHelper.getLong(BitBufferHelper.getBits(data, bitOffset + 12, 20)));
            builder.setIpv6Length(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 32, 16)));
            builder.setNextHeader(KnownIpProtocols
                    .forValue(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 48, 8))));
            builder.setHopLimit(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 56, 8)));
            builder.setSourceIpv6(Ipv6Address.getDefaultInstance(
                    InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset + 64, 128)).getHostAddress()));
            builder.setDestinationIpv6(Ipv6Address.getDefaultInstance(
                    InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset + 192, 128)).getHostAddress()));
            builder.setPayloadOffset((320 + bitOffset) / NetUtils.NUM_BITS_IN_A_BYTE);
            builder.setPayloadLength(builder.getIpv6Length());

            // Decode the optional "extension headers"
            List<ExtensionHeaders> extensionHeaders = new ArrayList<>();
            KnownIpProtocols nextHeader = builder.getNextHeader();
            int extHeaderOffset = 0;
            while (nextHeader != null && !nextHeader.equals(KnownIpProtocols.Tcp)
                    && !nextHeader.equals(KnownIpProtocols.Udp)) {
                // Set the extension header's type & length & data
                short nextHeaderType = BitBufferHelper
                        .getShort(BitBufferHelper.getBits(data, 320 + extHeaderOffset + bitOffset, 8));
                nextHeader = KnownIpProtocols.forValue(nextHeaderType);
                int octetLength = BitBufferHelper
                        .getInt(BitBufferHelper.getBits(data, 328 + extHeaderOffset + bitOffset, 8));
                int start = (336 + extHeaderOffset + bitOffset) / NetUtils.NUM_BITS_IN_A_BYTE;
                int end = start + 6 + octetLength;

                extensionHeaders.add(new ExtensionHeadersBuilder().setNextHeader(nextHeader).setLength(octetLength)
                        .setData(Arrays.copyOfRange(data, start, end)).build());

                // Update the NextHeader field
                extHeaderOffset += 64 + octetLength * NetUtils.NUM_BITS_IN_A_BYTE;
            }
            if (!extensionHeaders.isEmpty()) {
                builder.setExtensionHeaders(extensionHeaders);
            }
        } catch (BufferException | UnknownHostException e) {
            LOG.debug("Exception while decoding IPv4 packet", e.getMessage());
        }

        // build ipv6
        packetChainList.add(new PacketChainBuilder().setPacket(builder.build()).build());
        ipv6ReceivedBuilder.setPacketChain(packetChainList);

        // carry forward the original payload.
        ipv6ReceivedBuilder.setPayload(ethernetPacketReceived.getPayload());

        return ipv6ReceivedBuilder.build();
    }

    public  Ipv6Decoder(NotificationProviderService notificationProviderService);

}