Update to work on Sodium SR1
[l2switch.git] / packethandler / implementation / src / main / java / org / opendaylight / l2switch / packethandler / decoders / IcmpDecoder.java
1 /*
2  * Copyright (c) 2016 Hewlett Packard Enterprise, Co. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.l2switch.packethandler.decoders;
9
10 import java.util.List;
11 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
12 import org.opendaylight.l2switch.packethandler.decoders.utils.BitBufferHelper;
13 import org.opendaylight.l2switch.packethandler.decoders.utils.BufferException;
14 import org.opendaylight.l2switch.packethandler.decoders.utils.NetUtils;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.PacketChain;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.PacketChainBuilder;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.basepacket.rev140528.packet.chain.grp.packet.chain.Packet;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.icmp.rev140528.IcmpPacketReceived;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.icmp.rev140528.IcmpPacketReceivedBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.icmp.rev140528.icmp.packet.received.packet.chain.packet.IcmpPacketBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv4.rev140528.Ipv4PacketListener;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv4.rev140528.Ipv4PacketReceived;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv4.rev140528.KnownIpProtocols;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.ipv4.rev140528.ipv4.packet.received.packet.chain.packet.Ipv4Packet;
25 import org.opendaylight.yangtools.yang.binding.NotificationListener;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 public class IcmpDecoder extends AbstractPacketDecoder<Ipv4PacketReceived, IcmpPacketReceived>
30         implements Ipv4PacketListener {
31
32     private static final Logger LOG = LoggerFactory.getLogger(IcmpDecoder.class);
33
34     public IcmpDecoder(NotificationProviderService notificationProviderService) {
35         super(IcmpPacketReceived.class, notificationProviderService);
36     }
37
38     /**
39      * Decode an EthernetPacket into an IcmpPacket.
40      */
41     @Override
42     public IcmpPacketReceived decode(Ipv4PacketReceived ipv4PacketReceived) {
43         IcmpPacketReceivedBuilder icmpReceivedBuilder = new IcmpPacketReceivedBuilder();
44
45         // Find the latest packet in the packet-chain, which is an
46         // EthernetPacket
47         List<PacketChain> packetChainList = ipv4PacketReceived.getPacketChain();
48         Ipv4Packet ipv4Packet = (Ipv4Packet) packetChainList.get(packetChainList.size() - 1).getPacket();
49         int bitOffset = ipv4Packet.getPayloadOffset() * NetUtils.NUM_BITS_IN_A_BYTE;
50         byte[] data = ipv4PacketReceived.getPayload();
51
52         IcmpPacketBuilder builder = new IcmpPacketBuilder();
53         try {
54             // Decode the ICMP type and ICMP code
55             builder.setType(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 0, 8)));
56             builder.setCode(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 8, 8)));
57
58             // Decode the checksum
59             builder.setCrc(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 16, 16)));
60
61             // Decode the identifier and sequence number
62             builder.setIdentifier(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 32, 16)));
63             builder.setSequenceNumber(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 48, 16)));
64
65             // Decode the ICMP Payload
66             int payloadStartInBits = bitOffset + 64;
67             int payloadEndInBits = data.length * NetUtils.NUM_BITS_IN_A_BYTE - payloadStartInBits - 4
68                     * NetUtils.NUM_BITS_IN_A_BYTE;
69             int start = payloadStartInBits / NetUtils.NUM_BITS_IN_A_BYTE;
70             int end = start + payloadEndInBits / NetUtils.NUM_BITS_IN_A_BYTE;
71             builder.setPayloadOffset(start);
72             builder.setPayloadLength(end - start);
73         } catch (BufferException e) {
74             LOG.debug("Exception while decoding ICMP packet", e);
75         }
76
77         // build icmp
78         packetChainList.add(new PacketChainBuilder().setPacket(builder.build()).build());
79         icmpReceivedBuilder.setPacketChain(packetChainList);
80
81         // carry forward the original payload.
82         icmpReceivedBuilder.setPayload(ipv4PacketReceived.getPayload());
83
84         return icmpReceivedBuilder.build();
85     }
86
87     @Override
88     public NotificationListener getConsumedNotificationListener() {
89         return this;
90     }
91
92     @Override
93     public void onIpv4PacketReceived(Ipv4PacketReceived notification) {
94         decodeAndPublish(notification);
95     }
96
97     @Override
98     public boolean canDecode(Ipv4PacketReceived ipv4PacketReceived) {
99         if (ipv4PacketReceived == null || ipv4PacketReceived.getPacketChain() == null) {
100             return false;
101         }
102
103         // Only decode the latest packet in the chain
104         Ipv4Packet ipv4Packet = null;
105         if (!ipv4PacketReceived.getPacketChain().isEmpty()) {
106             Packet packet = ipv4PacketReceived.getPacketChain().get(ipv4PacketReceived.getPacketChain().size() - 1)
107                     .getPacket();
108             if (packet instanceof Ipv4Packet) {
109                 ipv4Packet = (Ipv4Packet) packet;
110             }
111         }
112
113         return ipv4Packet != null && KnownIpProtocols.Icmp.equals(ipv4Packet.getProtocol());
114     }
115 }