You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2017/11/14 01:48:32 UTC

[18/25] nifi-minifi-cpp git commit: MINIFICPP-250: Initial implementation fo CapturePacket Processor that uses lipcap.

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/IcmpLayer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/IcmpLayer.h b/thirdparty/pcap++/Packet++/header/IcmpLayer.h
new file mode 100644
index 0000000..c2d3400
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/IcmpLayer.h
@@ -0,0 +1,703 @@
+#ifndef PACKETPP_ICMP_LAYER
+#define PACKETPP_ICMP_LAYER
+
+#include <Layer.h>
+#include <IPv4Layer.h>
+#ifdef _MSC_VER
+#include <Winsock2.h>
+#else
+#include <sys/time.h>
+#endif
+#include <vector>
+
+
+/// @file
+
+/**
+ * \namespace pcpp
+ * \brief The main namespace for the PcapPlusPlus lib
+ */
+namespace pcpp
+{
+
+	/**
+	 * @struct icmphdr
+	 * Represents ICMP basic protocol header (common for all ICMP message types)
+	 */
+#pragma pack(push, 1)
+	typedef struct
+	{
+		/** message type */
+		uint8_t	 type;
+		/** message code */
+		uint8_t	 code;
+		/** message checksum */
+		uint16_t checksum;
+	} icmphdr;
+#pragma pack(pop)
+
+	/**
+	 * An enum of all supported ICMP message types
+	 */
+	enum IcmpMessageType
+	{
+		/** ICMP echo (ping) reply message */
+		ICMP_ECHO_REPLY           = 0,
+		/** ICMP destination unreachable message */
+		ICMP_DEST_UNREACHABLE     = 3,
+		/** ICMP source quench message */
+		ICMP_SOURCE_QUENCH        = 4,
+		/** ICMP redirect message */
+		ICMP_REDIRECT             = 5,
+		/** ICMP echo (ping) request message */
+		ICMP_ECHO_REQUEST         = 8,
+		/** ICMP router advertisement message */
+		ICMP_ROUTER_ADV           = 9,
+		/** ICMP router soliciatation message */
+		ICMP_ROUTER_SOL           = 10,
+		/** ICMP time-to-live excceded message */
+		ICMP_TIME_EXCEEDED        = 11,
+		/** ICMP parameter problem message */
+		ICMP_PARAM_PROBLEM        = 12,
+		/** ICMP timestamp request message */
+		ICMP_TIMESTAMP_REQUEST    = 13,
+		/** ICMP timestamp reply message */
+		ICMP_TIMESTAMP_REPLY      = 14,
+		/** ICMP information request message */
+		ICMP_INFO_REQUEST         = 15,
+		/** ICMP information reply message */
+		ICMP_INFO_REPLY           = 16,
+		/** ICMP address mask request message */
+		ICMP_ADDRESS_MASK_REQUEST = 17,
+		/** ICMP address mask reply message */
+		ICMP_ADDRESS_MASK_REPLY   = 18,
+		/** ICMP message type unsupported by PcapPlusPlus */
+		ICMP_UNSUPPORTED          = 255
+	};
+
+	/**
+	 * An enum for all possible codes for a destination unreachable message type
+	 * Documentation is taken from Wikipedia: https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol
+	 */
+	enum IcmpDestUnreachableCodes
+	{
+		/** Network unreachable error */
+		IcmpNetworkUnreachable = 0,
+		/** Host unreachable error */
+		IcmpHostUnreachable = 1,
+		/** Protocol unreachable error (the designated transport protocol is not supported) */
+		IcmpProtocolUnreachable = 2,
+		/** Port unreachable error (the designated protocol is unable to inform the host of the incoming message) */
+		IcmpPortUnreachable = 3,
+		/** The datagram is too big. Packet fragmentation is required but the 'don't fragment' (DF) flag is on */
+		IcmpDatagramTooBig = 4,
+		/** Source route failed error */
+		IcmpSourceRouteFailed = 5,
+		/** Destination network unknown error */
+		IcmpDestinationNetworkUnknown = 6,
+		/** Destination host unknown error */
+		IcmpDestinationHostUnknown = 7,
+		/** Source host isolated error */
+		IcmpSourceHostIsolated = 8,
+		/** The destination network is administratively prohibited */
+		IcmpDestinationNetworkProhibited = 9,
+		/** The destination host is administratively prohibited */
+		IcmpDestinationHostProhibited = 10,
+		/** The network is unreachable for Type Of Service */
+		IcmpNetworkUnreachableForTypeOfService = 11,
+		/** The host is unreachable for Type Of Service */
+		IcmpHostUnreachableForTypeOfService = 12,
+		/** Communication administratively prohibited (administrative filtering prevents
+		 * packet from being forwarded)
+		 */
+		IcmpCommunicationProhibited = 13,
+		/** Host precedence violation (indicates the requested precedence is not permitted for
+		 * the combination of host or network and port)
+		 */
+		IcmpHostPrecedenceViolation = 14,
+		/** Precedence cutoff in effect (precedence of datagram is below the level set by
+		 * the network administrators)
+		 */
+		IcmpPrecedenceCutoff = 15
+	};
+
+
+	/**
+	 * @struct icmp_echo_hdr
+	 * ICMP echo (ping) request/reply message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** the echo (ping) request identifier */
+		uint16_t id;
+		/** the echo (ping) request sequence number */
+		uint16_t sequence;
+		/** a timestamp of when the message was sent */
+		uint64_t timestamp;
+	} icmp_echo_hdr;
+#pragma pack(pop)
+
+
+	/**
+	 * @struct icmp_echo_request
+	 * ICMP echo (ping) request/reply message structure
+	 */
+	typedef struct
+	{
+		/** a pointer to the header data */
+		icmp_echo_hdr* header;
+		/** most echo requests/replies contain some payload data. This is the data length */
+		size_t dataLength;
+		/** most echo requests/replies contain some payload data. This is a pointer to this data */
+		uint8_t* data;
+	} icmp_echo_request;
+
+
+	/**
+	 * @typedef icmp_echo_reply
+	 * ICMP echo (ping) reply message structure, same as icmp_echo_request
+	 */
+	typedef icmp_echo_request icmp_echo_reply;
+
+
+	/**
+	 * @struct icmp_timestamp_request
+	 * ICMP timestamp request message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** the timestamp request identifier */
+		uint16_t id;
+		/** the timestamp request sequence number */
+		uint16_t sequence;
+		/** the time (in milliseconds since midnight) the sender last touched the packet */
+		uint32_t originateTimestamp;
+		/** relevant for timestamp reply only - the time the echoer first touched it on receipt */
+		uint32_t receiveTimestamp;
+		/** relevant for timestamp reply only - the time the echoer last touched the message on sending it */
+		uint32_t transmitTimestamp;
+	} icmp_timestamp_request;
+#pragma pack(pop)
+
+
+	/**
+	 * @typedef icmp_timestamp_reply
+	 * ICMP timestamp reply message structure, same as icmp_timestamp_request
+	 */
+	typedef icmp_timestamp_request icmp_timestamp_reply;
+
+
+	/**
+	 * @struct icmp_destination_unreachable
+	 * ICMP destination unreachable message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** unused 2 bytes */
+		uint16_t unused;
+		/** contains the MTU of the next-hop network if a code 4 error occurs */
+		uint16_t nextHopMTU;
+	} icmp_destination_unreachable;
+#pragma pack(pop)
+
+
+	/**
+	 * @struct icmp_time_exceeded
+	 * ICMP time-to-live exceeded message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** unused 4 bytes */
+		uint32_t unused;
+	} icmp_time_exceeded;
+#pragma pack(pop)
+
+
+	/**
+	 * @typedef icmp_source_quench
+	 * ICMP source quence message structure, same as icmp_time_exceeded
+	 */
+	typedef icmp_time_exceeded icmp_source_quench;
+
+
+	/**
+	 * @struct icmp_param_problem
+	 * ICMP parameter problem message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** in the case of an invalid IP header (Code 0), this field indicates the byte offset of the error in the header */
+		uint8_t  pointer;
+		/** unused 1 byte */
+		uint8_t  unused1;
+		/** unused 2 bytes */
+		uint16_t unused2;
+	} icmp_param_problem;
+#pragma pack(pop)
+
+
+	/**
+	 * @typedef icmp_router_solicitation
+	 * ICMP router solicitation message structure, same as icmphdr
+	 */
+	typedef icmphdr icmp_router_solicitation;
+
+	/**
+	 * @struct icmp_redirect
+	 * ICMP redirect message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** an IPv4 address of the gateway to which the redirection should be sent */
+		uint32_t gatewayAddress;
+	} icmp_redirect;
+#pragma pack(pop)
+
+
+	/**
+	 * @struct icmp_router_address_structure
+	 * Router address structure, relevant for ICMP router advertisement message type (icmp_router_advertisement)
+	 */
+#pragma pack(push, 1)
+	struct icmp_router_address_structure
+	{
+		/** the IPv4 address of the advertised router */
+		uint32_t routerAddress;
+		/** The preferability of the router address as a default router address, relative to other router addresses
+		 * on the same subnet. This is a twos-complement value where higher values indicate that the route is
+		 * more preferable */
+		uint32_t preferenceLevel;
+
+		/**
+		 * Set router address structure from a given IPv4 address and preference level
+		 * @param[in] addr IPv4 address to set
+		 * @param[in] preference Preference level to set
+		 */
+		void setRouterAddress(IPv4Address addr, uint32_t preference);
+
+		/**
+		 * @return The IPv4 address extracted from icmp_router_address_structure#routerAddress field
+		 */
+		IPv4Address getAddress();
+	};
+#pragma pack(pop)
+
+
+	/**
+	 * @struct icmp_router_advertisement_hdr
+	 * ICMP router advertisement message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** the number of router advertisements in this message. Each advertisement contains one router address/preference level pair */
+		uint8_t  advertisementCount;
+		/** the number of 32-bit words of information for each router address entry in the list. The value is normally set to 2
+		 * (router address + preference level) */
+		uint8_t  addressEntrySize;
+		/** the maximum number of seconds that the router addresses in this list may be considered valid */
+		uint16_t lifetime;
+	} icmp_router_advertisement_hdr;
+#pragma pack(pop)
+
+
+	/**
+	 * @struct icmp_router_advertisement
+	 * ICMP router advertisement message structure
+	 */
+	struct icmp_router_advertisement
+	{
+		/** a pointer to the header data on the packet */
+		icmp_router_advertisement_hdr* header;
+
+		/**
+		 * Extract router advertisement at a given index
+		 * @param[in] index The index of the router advertisement
+		 * @return A pointer to the router advertisement on the packet or null if index is out of range (less than zero or
+		 * greater than the number of router advertisement records on this message, determined by advertisementCount field)
+		 */
+		icmp_router_address_structure* getRouterAddress(int index);
+	};
+
+
+	/**
+	 * @struct icmp_address_mask_request
+	 * ICMP address mask request message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** the address mask request identifier */
+		uint16_t id;
+		/** the address mask request sequence */
+		uint16_t sequence;
+		/** the subnet mask of the requesting host */
+		uint32_t addressMask;
+	} icmp_address_mask_request;
+#pragma pack(pop)
+
+
+	/**
+	 * @typedef icmp_address_mask_reply
+	 * ICMP address mask reply message structure, same as icmp_address_mask_request
+	 */
+	typedef icmp_address_mask_request icmp_address_mask_reply;
+
+
+	/**
+	 * @struct icmp_info_request
+	 * ICMP information request message structure
+	 */
+#pragma pack(push, 1)
+	typedef struct : icmphdr
+	{
+		/** the information request identifier */
+		uint16_t id;
+		/** the information request sequence */
+		uint16_t sequence;
+	} icmp_info_request;
+#pragma pack(pop)
+
+
+	/**
+	 * @typedef icmp_info_reply
+	 * ICMP information reply message structure, same as icmp_info_request
+	 */
+	typedef icmp_info_request icmp_info_reply;
+
+
+	/**
+	 * @class IcmpLayer
+	 * Represents an ICMP protocol layer (for IPv4 only)
+	 */
+	class IcmpLayer : public Layer
+	{
+	private:
+		icmp_echo_request m_EchoData;
+		icmp_router_advertisement m_RouterAdvData;
+
+		bool cleanIcmpLayer();
+
+		bool setEchoData(IcmpMessageType echoType, uint16_t id, uint16_t sequence, uint64_t timestamp, const uint8_t* data, size_t dataLen);
+
+		bool setIpAndL4Layers(IPv4Layer* ipLayer, Layer* l4Layer);
+
+	public:
+		/**
+		 * A constructor that creates the layer from an existing packet raw data
+		 * @param[in] data A pointer to the raw data (will be casted to @ref arphdr)
+		 * @param[in] dataLen Size of the data in bytes
+		 * @param[in] prevLayer A pointer to the previous layer
+		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+		 */
+		IcmpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = ICMP; }
+
+		/**
+		 * An empty constructor that creates a new layer with an empty ICMP header without setting the ICMP type or ICMP data.
+		 * Call the set*Data() methods to set ICMP type and data
+		 */
+		IcmpLayer();
+
+		virtual ~IcmpLayer() {}
+
+		/**
+		 * Get a pointer to the basic ICMP header. Notice this points directly to the data, so every change will change the actual packet data
+		 * @return A pointer to the @ref icmphdr
+		 */
+		inline icmphdr* getIcmpHeader() { return (icmphdr*)m_Data; };
+
+		/**
+		 * @return The ICMP message type
+		 */
+		IcmpMessageType getMessageType();
+
+		/**
+		 * @param[in] type Type to check
+		 * @return True if the layer if of the given type, false otherwise
+		 */
+		bool isMessageOfType(IcmpMessageType type);
+
+		/**
+		 * @return ICMP echo (ping) request data. If the layer isn't of type ICMP echo request NULL is returned
+		 */
+		icmp_echo_request* getEchoRequestData();
+
+		/**
+		 * Set echo (ping) request message data
+		 * @param[in] id Echo (ping) request identifier
+		 * @param[in] sequence Echo (ping) request sequence
+		 * @param[in] timestamp Echo (ping) request timestamp
+		 * @param[in] data A pointer to echo (ping) request payload to set
+		 * @param[in] dataLen The length of the echo (ping) request payload
+		 * @return A pointer to the echo (ping) request data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_echo_request* setEchoRequestData(uint16_t id, uint16_t sequence, uint64_t timestamp, const uint8_t* data, size_t dataLen);
+
+		/**
+		 * @return ICMP echo reply data. If the layer isn't of type ICMP echo reply NULL is returned
+		 */
+		icmp_echo_reply* getEchoReplyData();
+
+		/**
+		 * Set echo (ping) reply message data
+		 * @param[in] id Echo (ping) reply identifier
+		 * @param[in] sequence Echo (ping) reply sequence
+		 * @param[in] timestamp Echo (ping) reply timestamp
+		 * @param[in] data A pointer to echo (ping) reply payload to set
+		 * @param[in] dataLen The length of the echo (ping) reply payload
+		 * @return A pointer to the echo (ping) reply data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_echo_reply* setEchoReplyData(uint16_t id, uint16_t sequence, uint64_t timestamp, const uint8_t* data, size_t dataLen);
+
+		/**
+		 * @return ICMP timestamp request data. If the layer isn't of type ICMP timestamp request NULL is returned
+		 */
+		icmp_timestamp_request* getTimestampRequestData();
+
+		/**
+		 * Set timestamp request message data
+		 * @param[in] id Timestamp request identifier
+		 * @param[in] sequence Timestamp request sequence
+		 * @param[in] originateTimestamp Time (in milliseconds since midnight) the sender last touched the packet
+		 * @return A pointer to the timestamp request data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_timestamp_request* setTimestampRequestData(uint16_t id, uint16_t sequence, timeval originateTimestamp);
+
+		/**
+		 * @return ICMP timestamp reply data. If the layer isn't of type ICMP timestamp reply NULL is returned
+		 */
+		icmp_timestamp_reply* getTimestampReplyData();
+
+		/**
+		 * Set timestamp reply message data
+		 * @param[in] id Timestamp reply identifier
+		 * @param[in] sequence Timestamp reply sequence
+		 * @param[in] originateTimestamp Time (in milliseconds since midnight) the sender last touched the packet
+		 * @param[in] receiveTimestamp The time the echoer first touched it on receipt
+		 * @param[in] transmitTimestamp The time the echoer last touched the message on sending it
+		 * @return A pointer to the timestamp reply data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_timestamp_reply* setTimestampReplyData(uint16_t id, uint16_t sequence,
+				timeval originateTimestamp, timeval receiveTimestamp, timeval transmitTimestamp);
+
+		/**
+		 * @return ICMP destination unreachable data. If the layer isn't of type ICMP destination unreachable NULL is returned.
+		 * The IP and L4 (ICMP/TCP/UDP) headers of the destination unreachable data are parsed as separate layers and can be
+		 * retrieved via this->getNextLayer()
+		 */
+		icmp_destination_unreachable* getDestUnreachableData();
+
+		/**
+		 * Set destination unreachable message data. This method only works if IcmpLayer is already part of a packet (not
+		 * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate layers
+		 * and need a packet to be added to
+		 * @param[in] code Destination unreachable code
+		 * @param[in] nextHopMTU The MTU of the next-hop network if a code 4 error occurs
+		 * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the packet
+		 * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet
+		 * @return A pointer to the destination unreachable data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_destination_unreachable* setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU, IPv4Layer* ipHeader, Layer* l4Header);
+
+		/**
+		 * @return ICMP source quench data. If the layer isn't of type ICMP source quench NULL is returned.
+		 * The IP and L4 (ICMP/TCP/UDP) headers of the source quench data are parsed as separate layers and can be
+		 * retrieved via this->getNextLayer()
+		 */
+		icmp_source_quench* getSourceQuenchdata();
+
+		/**
+		 * Set source quench message data. This method only works if IcmpLayer is already part of a packet (not
+		 * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate layers
+		 * and need a packet to be added to
+		 * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the packet
+		 * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet
+		 * @return A pointer to the source quench data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_source_quench* setSourceQuenchdata(IPv4Layer* ipHeader, Layer* l4Header);
+
+		/**
+		 * @return ICMP redirect data. If the layer isn't of type ICMP redirect NULL is returned.
+		 * The IP and L4 (ICMP/TCP/UDP) headers of the redirect data are parsed as separate layers and can be
+		 * retrieved via this->getNextLayer()
+		 */
+		icmp_redirect* getRedirectData();
+
+		/**
+		 * Set redirect message data. This method only works if IcmpLayer is already part of a packet (not
+		 * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate layers
+		 * and need a packet to be added to
+		 * @param[in] code The redirect message code. Only values between 0 and 3 are legal, the rest will cause the method to fail
+		 * @param[in] gatewayAddress An IPv4 address of the gateway to which the redirection should be sent
+		 * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the packet
+		 * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet
+		 * @return A pointer to the redirect data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_redirect* setRedirectData(uint8_t code, IPv4Address gatewayAddress, IPv4Layer* ipHeader, Layer* l4Header);
+
+		/**
+		 * @return ICMP router advertisement data. If the layer isn't of type ICMP router advertisement NULL is returned
+		 */
+		icmp_router_advertisement* getRouterAdvertisementData();
+
+		/**
+		 * Set router advertisement message data
+		 * @param[in] code The router advertisement message code. Only codes 0 or 16 are legal, the rest will fail the method
+		 * @param[in] lifetimeInSeconds The maximum number of seconds that the router addresses in this list may be considered valid
+		 * @param[in] routerAddresses A vector of router advertisements to set
+		 * @return A pointer to the router advertisement data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_router_advertisement* setRouterAdvertisementData(uint8_t code, uint16_t lifetimeInSeconds, const std::vector<icmp_router_address_structure>& routerAddresses);
+
+		/**
+		 * @return ICMP router solicitation data. If the layer isn't of type ICMP router solicitation NULL is returned
+		 */
+		icmp_router_solicitation* getRouterSolicitationData();
+
+		/**
+		 * Set router solicitation message data. This message accepts no parameters as there are no parameters to this
+		 * type of message (code is always zero)
+		 * @return A pointer to the router solicitation data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_router_solicitation* setRouterSolicitationData();
+
+		/**
+		 * @return ICMP time-to-live exceeded data. If the layer isn't of type ICMP time-to-live exceeded NULL is returned.
+		 * The IP and L4 (ICMP/TCP/UDP) headers of the time exceeded data are parsed as separate layers and can be
+		 * retrieved via this->getNextLayer()
+		 */
+		icmp_time_exceeded* getTimeExceededData();
+
+		/**
+		 * Set time-to-live exceeded message data. This method only works if IcmpLayer is already part of a packet (not
+		 * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate layers
+		 * and need a packet to be added to
+		 * @param[in] code Time-to-live exceeded message code. Only codes 0 or 1 are legal, the rest will fail the method
+		 * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the packet
+		 * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet
+		 * @return A pointer to the time-to-live exceeded data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_time_exceeded* setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header);
+
+		/**
+		 * @return ICMP parameter problem data. If the layer isn't of type ICMP parameter problem NULL is returned
+		 */
+		icmp_param_problem* getParamProblemData();
+
+		/**
+		 * Set parameter problem message data. This method only works if IcmpLayer is already part of a packet (not
+		 * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate layers
+		 * and need a packet to be added to
+		 * @param[in] code Parameter problem message code. Only code between 0 and 2 are legal, the rest will fail the method
+		 * @param[in] errorOctetPointer In the case of an invalid IP header (Code 0), indicate the byte offset of the error in the header
+		 * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the packet
+		 * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet
+		 * @return A pointer to the parameter problem data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_param_problem* setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader, Layer* l4Header);
+
+		/**
+		 * @return ICMP address mask request data. If the layer isn't of type ICMP address mask request NULL is returned
+		 */
+		icmp_address_mask_request* getAddressMaskRequestData();
+
+		/**
+		 * Set address mask request message data
+		 * @param[in] id Address mask request identifier
+		 * @param[in] sequence Address mask request sequence
+		 * @param[in] mask The subnet mask of the requesting host
+		 * @return A pointer to the address mask request data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_address_mask_request* setAddressMaskRequestData(uint16_t id, uint16_t sequence, IPv4Address mask);
+
+		/**
+		 * @return ICMP address mask reply data. If the layer isn't of type ICMP address mask reply NULL is returned
+		 */
+		icmp_address_mask_reply* getAddressMaskReplyData();
+
+		/**
+		 * Set address mask reply message data
+		 * @param[in] id Address mask reply identifier
+		 * @param[in] sequence Address mask reply sequence
+		 * @param[in] mask The subnet mask of the requesting host
+		 * @return A pointer to the address mask reply data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_address_mask_reply* setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask);
+
+		/**
+		 * @return ICMP address information request data. If the layer isn't of type ICMP information request NULL is returned
+		 */
+		icmp_info_request* getInfoRequestData();
+
+		/**
+		 * Set information request message data
+		 * @param[in] id Information request identifier
+		 * @param[in] sequence Information request sequence
+		 * @return A pointer to the information request data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_info_request* setInfoRequestData(uint16_t id, uint16_t sequence);
+
+		/**
+		 * @return ICMP address information reply data. If the layer isn't of type ICMP information reply NULL is returned
+		 */
+		icmp_info_reply* getInfoReplyData();
+
+		/**
+		 * Set information reply message data
+		 * @param[in] id Information reply identifier
+		 * @param[in] sequence Information reply sequence
+		 * @return A pointer to the information reply data that have been set or NULL if something went wrong
+		 * (an appropriate error log is printed in such cases)
+		 */
+		icmp_info_reply* setInfoReplyData(uint16_t id, uint16_t sequence);
+
+
+		// implement abstract methods
+
+		/**
+		 * ICMP messages of types: ICMP_DEST_UNREACHABLE, ICMP_SOURCE_QUENCH, ICMP_TIME_EXCEEDED, ICMP_REDIRECT, ICMP_PARAM_PROBLEM
+		 * have data that contains IPv4 header and some L4 header (TCP/UDP/ICMP). This method parses these headers as separate
+		 * layers on top of the ICMP layer
+		 */
+		void parseNextLayer();
+
+		/**
+		 * @return The ICMP header length. This length varies according to the ICMP message type. This length doesn't include
+		 * IPv4 and L4 headers in case ICMP message type are: ICMP_DEST_UNREACHABLE, ICMP_SOURCE_QUENCH, ICMP_TIME_EXCEEDED,
+		 * ICMP_REDIRECT, ICMP_PARAM_PROBLEM
+		 */
+		size_t getHeaderLen();
+
+		/**
+		 * Calculate ICMP checksum field
+		 */
+		void computeCalculateFields();
+
+		std::string toString();
+
+		OsiModelLayer getOsiModelLayer() { return OsiModelNetworkLayer; }
+	};
+
+} // namespace pcpp
+
+#endif /* PACKETPP_ICMP_LAYER */

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/IgmpLayer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/IgmpLayer.h b/thirdparty/pcap++/Packet++/header/IgmpLayer.h
new file mode 100644
index 0000000..61cb97a
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/IgmpLayer.h
@@ -0,0 +1,509 @@
+#ifndef PACKETPP_IGMP_LAYER
+#define PACKETPP_IGMP_LAYER
+
+#include <Layer.h>
+#include <IpAddress.h>
+#include <vector>
+
+/// @file
+
+/**
+ * \namespace pcpp
+ * \brief The main namespace for the PcapPlusPlus lib
+ */
+namespace pcpp
+{
+
+/**
+ * @struct igmp_header
+ * IGMPv1 and IGMPv2 basic protocol header
+ */
+struct igmp_header
+{
+	/** Indicates the message type. The enum for message type is pcpp::IgmpType */
+	uint8_t type;
+	/** Specifies the time limit for the corresponding report. The field has a resolution of 100 milliseconds */
+	uint8_t maxResponseTime;
+	/** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */
+	uint16_t checksum;
+	/** This is the multicast address being queried when sending a Group-Specific or Group-and-Source-Specific Query */
+	uint32_t groupAddress;
+};
+
+
+/**
+ * @struct igmpv3_query_header
+ * IGMPv3 membership query basic header
+ */
+struct igmpv3_query_header
+{
+	/** IGMP message type. Should always have value of membership query (::IgmpType_MembershipQuery)  */
+	uint8_t type;
+	/** This field specifies the maximum time (in 1/10 second) allowed before sending a responding report */
+	uint8_t maxResponseTime;
+	/** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */
+	uint16_t checksum;
+	/** This is the multicast address being queried when sending a Group-Specific or Group-and-Source-Specific Query */
+	uint32_t groupAddress;
+	/** Suppress Router-side Processing Flag + Querier's Robustness Variable */
+	uint8_t s_qrv;
+	/** Querier's Query Interval Code */
+	uint8_t qqic;
+	/** This field specifies the number of source addresses present in the Query */
+	uint16_t numOfSources;
+};
+
+
+/**
+ * @struct igmpv3_report_header
+ * IGMPv3 membership report basic header
+ */
+struct igmpv3_report_header
+{
+	/** IGMP message type. Should always have value of IGMPv3 membership report (::IgmpType_MembershipReportV3)  */
+	uint8_t type;
+	/** Unused byte */
+	uint8_t reserved1;
+	/** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */
+	uint16_t checksum;
+	/** Unused bytes */
+	uint16_t reserved2;
+	/** This field specifies the number of group records present in the Report */
+	uint16_t numOfGroupRecords;
+};
+
+
+/**
+ * @struct igmpv3_group_record
+ * A block of fields containing information pertaining to the sender's membership in a single multicast group on the interface
+ * from which the Report is sent. Relevant only for IGMPv3 membership report messages
+ */
+struct igmpv3_group_record
+{
+	/** Group record type */
+	uint8_t recordType;
+	/** Contains the length of the Auxiliary Data field in this Group Record. A value other than 0 isn't supported */
+	uint8_t auxDataLen;
+	/** Specifies how many source addresses are present in this Group Record */
+	uint16_t numOfSources;
+	/** Contains the IP multicast address to which this Group Record pertains */
+	uint32_t multicastAddress;
+	/** A vector of n IP unicast addresses, where n is the value in this record's Number of Sources field */
+	uint8_t sourceAddresses[];
+
+	/**
+	 * @return The multicast address in igmpv3_group_record#multicastAddress as IPv4Address instance
+	 */
+	IPv4Address getMulticastAddress();
+
+	/**
+	 * @return The number of source addresses in this group record
+	 */
+	uint16_t getSourceAdressCount();
+
+	/**
+	 * Get the source address at a certain index
+	 * @param[in] index The index of the source address in the group record
+	 * @return The source address in the requested index. If index is negative or higher than the number of source addresses in this
+	 * group record the value if IPv4Address#Zero is returned
+	 */
+	IPv4Address getSoruceAddressAtIndex(int index);
+
+	/**
+	 * @return The total size in bytes of the group record
+	 */
+	size_t getRecordLen();
+};
+
+
+/**
+ * IGMP message types
+ */
+enum IgmpType
+{
+	/** Unknown message type */
+	IgmpType_Unknown = 0,
+	/** IGMP Membership Query */
+	IgmpType_MembershipQuery = 0x11,
+	/** IGMPv1 Membership Report */
+	IgmpType_MembershipReportV1 = 0x12,
+	/** DVMRP */
+	IgmpType_DVMRP = 0x13,
+	/** PIM version 1 */
+	IgmpType_P1Mv1 = 0x14,
+	/** Cisco Trace Messages */
+	IgmpType_CiscoTrace = 0x15,
+	/** IGMPv2 Membership Report */
+	IgmpType_MembershipReportV2 = 0x16,
+	/** IGMPv2 Leave Group */
+	IgmpType_LeaveGroup = 0x17,
+	/** Multicast Traceroute Response */
+	IgmpType_MulticastTracerouteResponse = 0x1e,
+	/** Multicast Traceroute */
+	IgmpType_MulticastTraceroute = 0x1f,
+	/** IGMPv3 Membership Report */
+	IgmpType_MembershipReportV3 = 0x22,
+	/** MRD, Multicast Router Advertisement */
+	IgmpType_MulticastRouterAdvertisement = 0x30,
+	/** MRD, Multicast Router Solicitation */
+	IgmpType_MulticastRouterSolicitation = 0x31,
+	/** MRD, Multicast Router Termination */
+	IgmpType_MulticastRouterTermination = 0x32,
+};
+
+
+/**
+ * @class IgmpLayer
+ * A base class for all IGMP (Internet Group Management Protocol) protocol classes. This is an abstract class and cannot be instantiated,
+ * only its child classes can be instantiated. The inherited classes represent the different versions of the protocol:
+ * IGMPv1, IGMPv2 and IGMPv3
+ */
+class IgmpLayer : public Layer
+{
+protected:
+
+	IgmpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType igmpVer) : Layer(data, dataLen, NULL, packet) { m_Protocol = igmpVer; }
+
+	IgmpLayer(IgmpType type, const IPv4Address& groupAddr, uint8_t maxResponseTime, ProtocolType igmpVer);
+
+	uint16_t calculateChecksum();
+
+	size_t getHeaderSizeByVerAndType(ProtocolType igmpVer, IgmpType igmpType);
+public:
+
+	virtual ~IgmpLayer() {}
+
+	/**
+	 * Get a pointer to the raw IGMPv1/IGMPv2 header. Notice this points directly to the data, so every change will change the actual packet data
+	 * @return A pointer to the @ref igmp_header
+	 */
+	inline igmp_header* getIgmpHeader() { return (igmp_header*)m_Data; }
+
+	/**
+	 * @return The IPv4 multicast address stored igmp_header#groupAddress
+	 */
+	inline IPv4Address getGroupAddress() { return IPv4Address(getIgmpHeader()->groupAddress); }
+
+	/**
+	 * Set the IPv4 multicast address
+	 * @param[in] groupAddr The IPv4 address to set
+	 */
+	void setGroupAddress(const IPv4Address& groupAddr);
+
+	/**
+	 * @return IGMP type set in igmp_header#type as ::IgmpType enum. Notice that if igmp_header#type contains a value
+	 * that doesn't appear in the ::IgmpType enum, ::IgmpType_Unknown will be returned
+	 */
+	IgmpType getType();
+
+	/**
+	 * Set IGMP type (will be written to igmp_header#type field)
+	 * @param[in] type The type to set
+	 */
+	void setType(IgmpType type);
+
+	/**
+	 * A static method that gets raw IGMP data (byte stream) and returns the IGMP version of this IGMP message
+	 * @param[in] data The IGMP raw data (byte stream)
+	 * @param[in] dataLen Raw data length
+	 * @param[out] isQuery Return true if IGMP message type is ::IgmpType_MembershipQuery and false otherwise
+	 * @return One of the values ::IGMPv1, ::IGMPv2, ::IGMPv3 according to detected IGMP version or ::UnknownProtocol if couldn't detect
+	 * IGMP version
+	 */
+	static ProtocolType getIGMPVerFromData(uint8_t* data, size_t dataLen, bool& isQuery);
+
+
+	// implement abstract methods
+
+	/**
+	 * Does nothing for this layer (IGMP layer is always last)
+	 */
+	void parseNextLayer() {}
+
+	/**
+	 * @return Size of IGMP header = 8B
+	 */
+	inline size_t getHeaderLen() { return sizeof(igmp_header); }
+
+	std::string toString();
+
+	OsiModelLayer getOsiModelLayer() { return OsiModelNetworkLayer; }
+};
+
+
+/**
+ * @class IgmpV1Layer
+ * Represents IGMPv1 (Internet Group Management Protocol ver 1) layer. This class represents all the different messages of IGMPv1
+ */
+class IgmpV1Layer : public IgmpLayer
+{
+public:
+	 /** A constructor that creates the layer from an existing packet raw data
+	 * @param[in] data A pointer to the raw data
+	 * @param[in] dataLen Size of the data in bytes
+	 * @param[in] prevLayer A pointer to the previous layer
+	 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+	 */
+	IgmpV1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
+
+	/**
+	 * A constructor that allocates a new IGMPv1 header
+	 * @param[in] type The message type to set
+	 * @param[in] groupAddr The multicast address to set. This is an optional parameter and has a default value of IPv4Address#Zero
+	 * if not provided
+	 */
+	IgmpV1Layer(IgmpType type, const IPv4Address& groupAddr = IPv4Address::Zero);
+
+	/**
+	 * A destructor for this layer (does nothing)
+	 */
+	~IgmpV1Layer() {}
+
+
+	// implement abstract methods
+
+	/**
+	 * Calculate the IGMP checksum and set igmp_header#maxResponseTime to 0 (this field is unused in IGMPv1)
+	 */
+	void computeCalculateFields();
+
+};
+
+
+/**
+ * @class IgmpV2Layer
+ * Represents IGMPv2 (Internet Group Management Protocol ver 2) layer. This class represents all the different messages of IGMPv2
+ */
+class IgmpV2Layer : public IgmpLayer
+{
+public:
+	 /** A constructor that creates the layer from an existing packet raw data
+	 * @param[in] data A pointer to the raw data
+	 * @param[in] dataLen Size of the data in bytes
+	 * @param[in] prevLayer A pointer to the previous layer
+	 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+	 */
+	IgmpV2Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
+
+	/**
+	 * A constructor that allocates a new IGMPv2 header
+	 * @param[in] type The message type to set
+	 * @param[in] groupAddr The multicast address to set. This is an optional parameter and has a default value of IPv4Address#Zero
+	 * @param[in] maxResponseTime The max response time to set. This is an optional parameter and has a default value of 0 if not provided
+	 */
+	IgmpV2Layer(IgmpType type, const IPv4Address& groupAddr = IPv4Address::Zero, uint8_t maxResponseTime = 0);
+
+	/**
+	 * A destructor for this layer (does nothing)
+	 */
+	~IgmpV2Layer() {}
+
+
+	// implement abstract methods
+
+	/**
+	 * Calculate the IGMP checksum
+	 */
+	void computeCalculateFields();
+};
+
+
+/**
+ * @class IgmpV3QueryLayer
+ * Represents an IGMPv3 (Internet Group Management Protocol ver 3) membership query message
+ */
+class IgmpV3QueryLayer : public IgmpLayer
+{
+public:
+
+	 /** A constructor that creates the layer from an existing packet raw data
+	 * @param[in] data A pointer to the raw data
+	 * @param[in] dataLen Size of the data in bytes
+	 * @param[in] prevLayer A pointer to the previous layer
+	 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+	 */
+	IgmpV3QueryLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
+
+	/**
+	 * A constructor that allocates a new IGMPv3 membership query
+	 * @param[in] multicastAddr The multicast address to set. This is an optional parameter and has a default value of IPv4Address#Zero
+	 * if not provided
+	 * @param[in] maxResponseTime The max response time to set. This is an optional parameter and has a default value of 0 if not provided
+	 * @param[in] s_qrv A 1-byte value representing the value in Suppress Router-side Processing Flag + Querier's Robustness Variable
+	 * (igmpv3_query_header#s_qrv field). This is an optional parameter and has a default value of 0 if not provided
+	 */
+	IgmpV3QueryLayer(const IPv4Address& multicastAddr = IPv4Address::Zero, uint8_t maxResponseTime = 0, uint8_t s_qrv = 0);
+
+	/**
+	 * Get a pointer to the raw IGMPv3 membership query header. Notice this points directly to the data, so every change will change the
+	 * actual packet data
+	 * @return A pointer to the @ref igmpv3_query_header
+	 */
+	inline igmpv3_query_header* getIgmpV3QueryHeader() { return (igmpv3_query_header*)m_Data; }
+
+	/**
+	 * @return The number of source addresses in this message (as extracted from the igmpv3_query_header#numOfSources field)
+	 */
+	uint16_t getSourceAddressCount();
+
+	/**
+	 * Get the IPV4 source address in a certain index
+	 * @param[in] index The requested index of the source address
+	 * @return The IPv4 source address, or IPv4Address#Zero if index is out of bounds (of the message or of the layer)
+	 */
+	IPv4Address getSourceAddressAtIndex(int index);
+
+	/**
+	 * Add a new source address at the end of the source address list. The igmpv3_query_header#numOfSources field will be incremented accordingly
+	 * @param[in] addr The IPv4 source address to add
+	 * @return True if source address was added successfully or false otherwise. If false is returned an appropriate error message
+	 * will be printed to log
+	 */
+	bool addSourceAddress(const IPv4Address& addr);
+
+	/**
+	 * Add a new source address at a certain index of the source address list. The igmpv3_query_header#numOfSources field will be incremented accordingly
+	 * @param[in] addr The IPv4 source address to add
+	 * @param[in] index The index to add the new source address at
+	 * @return True if source address was added successfully or false otherwise. If false is returned an appropriate error message
+	 * will be printed to log
+	 */
+	bool addSourceAddressAtIndex(const IPv4Address& addr, int index);
+
+	/**
+	 * Remove a source address at a certain index. The igmpv3_query_header#numOfSources field will be decremented accordingly
+	 * @param[in] index The index of the source address to be removed
+	 * @return True if source address was removed successfully or false otherwise. If false is returned an appropriate error message
+	 * will be printed to log
+	 */
+	bool removeSourceAddressAtIndex(int index);
+
+	/**
+	 * Remove all source addresses in the message. The igmpv3_query_header#numOfSources field will be set to 0
+	 * @return True if all source addresses were cleared successfully or false otherwise. If false is returned an appropriate error message
+	 * will be printed to log
+	 */
+	bool removeAllSourceAddresses();
+
+	// implement abstract methods
+
+	/**
+	 * Calculate the IGMP checksum
+	 */
+	void computeCalculateFields();
+
+	/**
+	 * @return The message size in bytes which include the size of the basic header + the size of the source address list
+	 */
+	size_t getHeaderLen();
+};
+
+
+/**
+ * @class IgmpV3ReportLayer
+ * Represents an IGMPv3 (Internet Group Management Protocol ver 3) membership report message
+ */
+class IgmpV3ReportLayer : public IgmpLayer
+{
+private:
+	igmpv3_group_record* addGroupRecordAt(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses, int offset);
+
+public:
+
+	 /** A constructor that creates the layer from an existing packet raw data
+	 * @param[in] data A pointer to the raw data
+	 * @param[in] dataLen Size of the data in bytes
+	 * @param[in] prevLayer A pointer to the previous layer
+	 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+	 */
+	IgmpV3ReportLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
+
+	/**
+	 * A constructor that allocates a new IGMPv3 membership report with 0 group addresses
+	 */
+	IgmpV3ReportLayer();
+
+	/**
+	 * Get a pointer to the raw IGMPv3 membership report header. Notice this points directly to the data, so every change will change the
+	 * actual packet data
+	 * @return A pointer to the @ref igmpv3_report_header
+	 */
+	inline igmpv3_report_header* getReportHeader() { return (igmpv3_report_header*)m_Data; }
+
+	/**
+	 * @return The number of group records in this message (as extracted from the igmpv3_report_header#numOfGroupRecords field)
+	 */
+	uint16_t getGroupRecordCount();
+
+	/**
+	 * @return A pointer to the first group record or NULL if no group records exist. Notice the return value is a pointer to the real data,
+	 * so changes in the return value will affect the packet data
+	 */
+	igmpv3_group_record* getFirstGroupRecord();
+
+	/**
+	 * Get the group record that comes next to a given group record. If "groupRecord" is NULL then NULL will be returned.
+	 * If "groupRecord" is the last group record or if it is out of layer bounds NULL will be returned also. Notice the return value is a
+	 * pointer to the real data casted to igmpv3_group_record type (as opposed to a copy of the option data). So changes in the return
+	 * value will affect the packet data
+	 * @param[in] groupRecord The group record to start searching from
+	 * @return The next group record or NULL if "groupRecord" is NULL, last or out of layer bounds
+	 */
+	igmpv3_group_record* getNextGroupRecord(igmpv3_group_record* groupRecord);
+
+	/**
+	 * Add a new group record at a the end of the group record list. The igmpv3_report_header#numOfGroupRecords field will be
+	 * incremented accordingly
+	 * @param[in] recordType The type of the new group record
+	 * @param[in] multicastAddress The multicast address of the new group record
+	 * @param[in] sourceAddresses A vector containing all the source addresses of the new group record
+	 * @return The method constructs a new group record, adds it to the end of the group record list of IGMPv3 report message and
+	 * returns a pointer to the new message. If something went wrong in creating or adding the new group record a NULL value is returned
+	 * and an appropriate error message is printed to log
+	 */
+	igmpv3_group_record* addGroupRecord(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses);
+
+	/**
+	 * Add a new group record at a certain index of the group record list. The igmpv3_report_header#numOfGroupRecords field will be
+	 * incremented accordingly
+	 * @param[in] recordType The type of the new group record
+	 * @param[in] multicastAddress The multicast address of the new group record
+	 * @param[in] sourceAddresses A vector containing all the source addresses of the new group record
+	 * @param[in] index The index to add the new group address at
+	 * @return The method constructs a new group record, adds it to the IGMPv3 report message and returns a pointer to the new message.
+	 * If something went wrong in creating or adding the new group record a NULL value is returned and an appropriate error message is
+	 * printed to log
+	 */
+	igmpv3_group_record* addGroupRecordAtIndex(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses, int index);
+
+	/**
+	 * Remove a group record at a certain index. The igmpv3_report_header#numOfGroupRecords field will be decremented accordingly
+	 * @param[in] index The index of the group record to be removed
+	 * @return True if group record was removed successfully or false otherwise. If false is returned an appropriate error message
+	 * will be printed to log
+	 */
+	bool removeGroupRecordAtIndex(int index);
+
+	/**
+	 * Remove all group records in the message. The igmpv3_report_header#numOfGroupRecords field will be set to 0
+	 * @return True if all group records were cleared successfully or false otherwise. If false is returned an appropriate error message
+	 * will be printed to log
+	 */
+	bool removeAllGroupRecords();
+
+	// implement abstract methods
+
+	/**
+	 * Calculate the IGMP checksum
+	 */
+	void computeCalculateFields();
+
+	/**
+	 * @return The message size in bytes which include the size of the basic header + the size of the group record list
+	 */
+	size_t getHeaderLen();
+};
+
+}
+
+#endif // PACKETPP_IGMP_LAYER

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/Layer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/Layer.h b/thirdparty/pcap++/Packet++/header/Layer.h
new file mode 100644
index 0000000..92b1dd2
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/Layer.h
@@ -0,0 +1,167 @@
+#ifndef PACKETPP_LAYER
+#define PACKETPP_LAYER
+
+#include <stdint.h>
+#include <stdio.h>
+#include "ProtocolType.h"
+#include <string>
+
+/// @file
+
+/**
+ * \namespace pcpp
+ * \brief The main namespace for the PcapPlusPlus lib
+ */
+namespace pcpp
+{
+
+	class Packet;
+
+	/**
+	 * @class Layer
+	 * Layer is the base class for all protocol layers. Each protocol supported in PcapPlusPlus has a class that inherits Layer.
+	 * The protocol layer class expose all properties and methods relevant for viewing and editing protocol fields.
+	 * For example: a pointer to a structured header (e.g tcphdr, iphdr, etc.), protocol header size, payload size, compute
+	 * fields that can be automatically computed, print protocol data to string, etc.
+	 * Each protocol instance is obviously part of a protocol stack (which construct a packet). This protocol stack is represented
+	 * in PcapPlusPlus in a linked list, and each layer is an element in this list. That's why each layer has proprties to the next and previous
+	 * layer in the protocol stack
+	 * The Layer class, as a base class, is abstract and the user can't create an instance of it (it has a private constructor)
+	 * Each layer holds a pointer to the relevant place in the packet. The layer sees all the data from this pointer forward until the
+	 * end of the packet. Here is an example packet showing this concept:
+	 *
+	  @verbatim
+
+	  ====================================================
+	  |Eth       |IPv4       |TCP       |Packet          |
+	  |Header    |Header     |Header    |Payload         |
+	  ====================================================
+
+	  |--------------------------------------------------|
+	  EthLayer data
+				 |---------------------------------------|
+				 IPv4Layer data
+							 |---------------------------|
+							 TcpLayer data
+										|----------------|
+										PayloadLayer data
+
+	  @endverbatim
+	 *
+	*/
+	class Layer {
+		friend class Packet;
+	public:
+		/**
+		 * A destructor for this class. Frees the data if it was allocated by the layer constructor (see isAllocatedToPacket() for more info)
+		 */
+		virtual ~Layer();
+
+		/**
+		 * @return A pointer to the next layer in the protocol stack or NULL if the layer is the last one
+		 */
+		inline Layer* getNextLayer() { return m_NextLayer; }
+
+		/**
+		 * @return A pointer to the previous layer in the protocol stack or NULL if the layer is the first one
+		 */
+		inline Layer* getPrevLayer() { return m_PrevLayer; }
+
+		/**
+		 * @return The protocol enum
+		 */
+		inline ProtocolType getProtocol() { return m_Protocol; }
+
+		/**
+		 * @return A pointer to the layer raw data. In most cases it'll be a pointer to the first byte of the header
+		 */
+		inline uint8_t* getData() { return m_Data; }
+
+		/**
+		 * @return The length in bytes of the data from the first byte of the header until the end of the packet
+		 */
+		inline size_t getDataLen() { return m_DataLen; }
+
+		/**
+		 * @return A pointer for the layer payload, meaning the first byte after the header
+		 */
+		uint8_t* getLayerPayload() { return m_Data + getHeaderLen(); }
+
+		/**
+		 * @return The size in bytes of the payload
+		 */
+		size_t getLayerPayloadSize() { return m_DataLen - getHeaderLen(); }
+
+		/**
+		 * Raw data in layers can come from one of sources:
+		 * 1. from an existing packet - this is the case when parsing packets received from files or the network. In this case the data was
+		 * already allocated by someone else, and layer only holds the pointer to the relevant place inside this data
+		 * 2. when creating packets, data is allocated when layer is created. In this case the layer is responsible for freeing it as well
+		 *
+		 * @return Returns true if the data was allocated by an external source (a packet) or false if it was allocated by the layer itself
+		 */
+		inline bool isAllocatedToPacket() { return m_Packet != NULL; }
+
+		/**
+		 * Copy the raw data of this layer to another array
+		 * @param[out] toArr The destination byte array
+		 */
+		void copyData(uint8_t* toArr);
+
+
+		// abstract methods
+
+		/**
+		 * Each layer is responsible for parsing the next layer
+		 */
+		virtual void parseNextLayer() = 0;
+
+		/**
+		 * @return The header length in bytes
+		 */
+		virtual size_t getHeaderLen() = 0;
+
+		/**
+		 * Each layer can compute field values automatically using this method. This is an abstract method
+		 */
+		virtual void computeCalculateFields() = 0;
+
+		/**
+		 * @return A string representation of the layer most important data (should look like the layer description in Wireshark)
+		 */
+		virtual std::string toString() = 0;
+
+		/**
+		 * @return The OSI Model layer this protocol belongs to
+		 */
+		virtual OsiModelLayer getOsiModelLayer() = 0;
+
+	protected:
+		uint8_t* m_Data;
+		size_t m_DataLen;
+		Packet* m_Packet;
+		ProtocolType m_Protocol;
+		Layer* m_NextLayer;
+		Layer* m_PrevLayer;
+
+		Layer() : m_Data(NULL), m_DataLen(0), m_Packet(NULL), m_Protocol(UnknownProtocol), m_NextLayer(NULL), m_PrevLayer(NULL) { }
+
+		Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) :
+			m_Data(data), m_DataLen(dataLen),
+			m_Packet(packet), m_Protocol(UnknownProtocol),
+			m_NextLayer(NULL), m_PrevLayer(prevLayer) {}
+
+		// Copy c'tor
+		Layer(const Layer& other);
+		Layer& operator=(const Layer& other);
+
+		inline void setNextLayer(Layer* nextLayer) { m_NextLayer = nextLayer; }
+		inline void setPrevLayer(Layer* prevLayer) { m_PrevLayer = prevLayer; }
+
+		virtual bool extendLayer(int offsetInLayer, size_t numOfBytesToExtend);
+		virtual bool shortenLayer(int offsetInLayer, size_t numOfBytesToShorten);
+	};
+
+} // namespace pcpp
+
+#endif /* PACKETPP_LAYER */

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/MplsLayer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/MplsLayer.h b/thirdparty/pcap++/Packet++/header/MplsLayer.h
new file mode 100644
index 0000000..1bc92d1
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/MplsLayer.h
@@ -0,0 +1,126 @@
+#ifndef PACKETPP_MPLS_LAYER
+#define PACKETPP_MPLS_LAYER
+
+#include <Layer.h>
+
+/// @file
+
+/**
+ * \namespace pcpp
+ * \brief The main namespace for the PcapPlusPlus lib
+ */
+namespace pcpp
+{
+
+	/**
+	 * @class MplsLayer
+	 * Represents a MPLS (Multi-Protocol Label Switching) layer
+	 */
+	class MplsLayer : public Layer
+	{
+	private:
+
+		#pragma pack(push, 1)
+		struct mpls_header
+		{
+			uint16_t    hiLabel;
+			uint8_t		misc;
+			uint8_t		ttl;
+		};
+		#pragma pack(pop)
+
+		inline mpls_header* getMplsHeader() { return (mpls_header*)m_Data; };
+
+	public:
+		 /** A constructor that creates the layer from an existing packet raw data
+		 * @param[in] data A pointer to the raw data
+		 * @param[in] dataLen Size of the data in bytes
+		 * @param[in] prevLayer A pointer to the previous layer
+		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+		 */
+		MplsLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = MPLS; }
+
+		/**
+		 * A constructor that allocates a new MPLS header
+		 * @param[in] mplsLabel MPLS label
+		 * @param[in] ttl Time-to-leave value
+		 * @param[in] expermentalUseValue Experimental use value
+		 * @param[in] bottomOfStack Bottom-of-stack value which indicate whether the next layer will also be a MPLS label or not
+		 */
+		MplsLayer(uint32_t mplsLabel, uint8_t ttl, uint8_t expermentalUseValue, bool bottomOfStack);
+
+		virtual ~MplsLayer() {}
+
+		/**
+		 * @return TTL value of the MPLS header
+		 */
+		inline uint8_t getTTL() { return getMplsHeader()->ttl; }
+
+		/**
+		 * Set the TTL value
+		 * @param[in] ttl The TTL value to set
+		 */
+		inline void setTTL(uint8_t ttl) { getMplsHeader()->ttl = ttl; }
+
+		/**
+		 * Get an indication whether the next layer is also be a MPLS label or not
+		 * @return True if it's the last MPLS layer, false otherwise
+		 */
+		bool isBottomOfStack();
+
+		/**
+		 * Set the bottom-of-stack bit in the MPLS label
+		 * @param[in] val Set or unset the bit
+		 */
+		void setBottomOfStack(bool val);
+
+		/**
+		 * @return The exp value (3 bits) of the MPLS label
+		 */
+		uint8_t getExperimentalUseValue();
+
+		/**
+		 * Set the exp value (3 bits) of the MPLS label
+		 * @param[in] val The exp value to set. val must be a valid number meaning between 0 and 7 (inclusive)
+		 * @return True if exp value was set successfully or false if val has invalid value
+		 */
+		bool setExperimentalUseValue(uint8_t val);
+
+		/**
+		 * @return The MPLS label value (20 bits)
+		 */
+		uint32_t getMplsLabel();
+
+		/**
+		 * Set the MPLS label (20 bits)
+		 * @param[in] label The label to set. label must be a valid number meaning between 0 and 0xFFFFF (inclusive)
+		 * @return True if label was set successfully or false if label has invalid value
+		 */
+		bool setMplsLabel(uint32_t label);
+
+		// implement abstract methods
+
+		/**
+		 * Currently identifies the following next layers: IPv4Layer, IPv6Layer, MplsLayer. Otherwise sets PayloadLayer
+		 */
+		void parseNextLayer();
+
+		/**
+		 * @return Size of MPLS header (4 bytes)
+		 */
+		inline size_t getHeaderLen() { return sizeof(mpls_header); }
+
+		/**
+		 * Set/unset the bottom-of-stack bit according to next layer: if it's a MPLS layer then bottom-of-stack will be unset. If it's not a
+		 * MPLS layer this bit will be set
+		 */
+		void computeCalculateFields();
+
+		std::string toString();
+
+		OsiModelLayer getOsiModelLayer() { return OsiModelNetworkLayer; }
+	};
+
+} // namespace pcpp
+
+#endif /* PACKETPP_MPLS_LAYER */

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/NullLoopbackLayer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/NullLoopbackLayer.h b/thirdparty/pcap++/Packet++/header/NullLoopbackLayer.h
new file mode 100644
index 0000000..05c2fe7
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/NullLoopbackLayer.h
@@ -0,0 +1,92 @@
+#ifndef PACKETPP_NULL_LOOPBACK_LAYER
+#define PACKETPP_NULL_LOOPBACK_LAYER
+
+/// @file
+
+#include <Layer.h>
+
+namespace pcpp
+{
+
+	/** IPv4 protocol **/
+	#define PCPP_BSD_AF_INET          2
+	/** XEROX NS protocols */
+	#define PCPP_BSD_AF_NS            6
+	/** ISO */
+	#define PCPP_BSD_AF_ISO           7
+	/** AppleTalk */
+	#define PCPP_BSD_AF_APPLETALK     16
+	/** IPX */
+	#define PCPP_BSD_AF_IPX           23
+	/** OpenBSD (and probably NetBSD), BSD/OS IPv6 */
+	#define PCPP_BSD_AF_INET6_BSD     24
+	/** FreeBSD IPv6 */
+	#define PCPP_BSD_AF_INET6_FREEBSD 28
+	/** Darwin IPv6 */
+	#define PCPP_BSD_AF_INET6_DARWIN  30
+
+	/**
+	 * @class NullLoopbackLayer
+	 * Represents a NULL/Loopback layer
+	 */
+	class NullLoopbackLayer : public Layer
+	{
+	public:
+		 /** A constructor that creates the layer from an existing packet raw data
+		 * @param[in] data A pointer to the raw data
+		 * @param[in] dataLen Size of the data in bytes
+		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+		 */
+		NullLoopbackLayer(uint8_t* data, size_t dataLen, Packet* packet) : Layer(data, dataLen, NULL, packet) { m_Protocol = NULL_LOOPBACK; }
+
+		/**
+		 * A constructor that allocates a new Null/Loopback header
+		 * @param[in] family The family protocol to set
+		 */
+		NullLoopbackLayer(uint32_t family);
+
+		/**
+		 * A destructor for this layer (does nothing)
+		 */
+		~NullLoopbackLayer() {}
+
+		/**
+		 * @return The protocol family in this layer
+		 */
+		uint32_t getFamily();
+
+		/**
+		 * Set a protocol family
+		 * @param[in] family The family protocol to set
+		 */
+		void setFamily(uint32_t family);
+
+
+		// implement abstract methods
+
+		/**
+		 * Identifies the next layers by family:
+		 * - for ::PCPP_BSD_AF_INET the next layer is IPv4Layer
+		 * - for ::PCPP_BSD_AF_INET6_BSD, ::PCPP_BSD_AF_INET6_FREEBSD, ::PCPP_BSD_AF_INET6_DARWIN the next layer is IPv6Layer
+		 * - for other values the next layer in PayloadLayer (unknown protocol)
+		 */
+		void parseNextLayer();
+
+		/**
+		 * @return Size of Null/Loopback header = 4B
+		 */
+		inline size_t getHeaderLen() { return sizeof(uint32_t); }
+
+		/**
+		 * Does nothing for this layer
+		 */
+		void computeCalculateFields() {}
+
+		std::string toString();
+
+		OsiModelLayer getOsiModelLayer() { return OsiModelDataLinkLayer; }
+	};
+
+} // namespace pcpp
+
+#endif /* PACKETPP_NULL_LOOPBACK_LAYER */

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/PPPoELayer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/PPPoELayer.h b/thirdparty/pcap++/Packet++/header/PPPoELayer.h
new file mode 100644
index 0000000..3bf728b
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/PPPoELayer.h
@@ -0,0 +1,661 @@
+#ifndef PACKETPP_PPPOE_LAYER
+#define PACKETPP_PPPOE_LAYER
+
+#include <Layer.h>
+#include <vector>
+#include <string.h>
+
+/// @file
+
+/**
+ * \namespace pcpp
+ * \brief The main namespace for the PcapPlusPlus lib
+ */
+namespace pcpp
+{
+
+	/**
+	 * @struct pppoe_header
+	 * Represents an PPPoE protocol header
+	 */
+#pragma pack(push, 1)
+	struct pppoe_header {
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+		/** PPPoE version */
+		uint8_t version:4,
+		/** PPPoE type */
+				type:4;
+		/** PPPoE code */
+		uint8_t code;
+#else
+		/** PPPoE version */
+		uint16_t version:4,
+		/** PPPoE type */
+				type:4,
+		/** PPPoE code */
+				code:8;
+#endif
+		/** PPPoE session ID (relevant for PPPoE session packets only) */
+		uint16_t sessionId;
+		/** Length (in bytes) of payload, not including the PPPoE header */
+		uint16_t payloadLength;
+	};
+#pragma pack(pop)
+
+
+	/**
+	 * @class PPPoELayer
+	 * An abstract class that describes the PPPoE protocol. Contains common data and logic of the two types of PPPoE packets: PPPoE session
+	 * and PPPoE discovery
+	 */
+	class PPPoELayer : public Layer
+	{
+	public:
+		/**
+		 * PPPoE possible codes
+		 */
+		enum PPPoECode
+		{
+			/** PPPoE session code */
+			PPPOE_CODE_SESSION	= 0x00,
+			/** PPPoE discovery PADO */
+			PPPOE_CODE_PADO		= 0x07,
+			/** PPPoE discovery PADI */
+			PPPOE_CODE_PADI		= 0x09,
+			/** PPPoE discovery PADG */
+			PPPOE_CODE_PADG		= 0x0a,
+			/** PPPoE discovery PADC */
+			PPPOE_CODE_PADC		= 0x0b,
+			/** PPPoE discovery PADQ */
+			PPPOE_CODE_PADQ		= 0x0c,
+			/** PPPoE discovery PADR */
+			PPPOE_CODE_PADR		= 0x19,
+			/** PPPoE discovery PADS */
+			PPPOE_CODE_PADS		= 0x65,
+			/** PPPoE discovery PADT */
+			PPPOE_CODE_PADT		= 0xa7,
+			/** PPPoE discovery PADM */
+			PPPOE_CODE_PADM		= 0xd3,
+			/** PPPoE discovery PADN */
+			PPPOE_CODE_PADN		= 0xd4
+		};
+
+		~PPPoELayer() {}
+
+		/**
+		 * Get a pointer to the PPPoE header. Notice this points directly to the data, so every change will change the actual packet data
+		 * @return A pointer to the pppoe_header
+		 */
+		inline pppoe_header* getPPPoEHeader() { return (pppoe_header*)m_Data; };
+
+		// abstract methods implementation
+
+		/**
+		 * Calculate @ref pppoe_header#payloadLength field
+		 */
+		virtual void computeCalculateFields();
+
+		OsiModelLayer getOsiModelLayer() { return OsiModelDataLinkLayer; }
+
+	protected:
+
+		// protected c'tor as this class shouldn't be instantiated
+		PPPoELayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : Layer(data, dataLen, prevLayer, packet) { }
+
+		// protected c'tor as this class shouldn't be instantiated
+		PPPoELayer(uint8_t version, uint8_t type, PPPoELayer::PPPoECode code, uint16_t sessionId, size_t additionalBytesToAllocate = 0);
+
+	};
+
+
+	/**
+	 * @class PPPoESessionLayer
+	 * Describes the PPPoE session protocol
+	 */
+	class PPPoESessionLayer : public PPPoELayer
+	{
+	public:
+
+		/**
+		 * A constructor that creates the layer from an existing packet raw data
+		 * @param[in] data A pointer to the raw data (will be casted to @ref pppoe_header)
+		 * @param[in] dataLen Size of the data in bytes
+		 * @param[in] prevLayer A pointer to the previous layer
+		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+		 */
+		PPPoESessionLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : PPPoELayer(data, dataLen, prevLayer, packet) { m_Protocol = PPPoESession; }
+
+		/**
+		 * A constructor that allocates a new PPPoE Session header with version, type and session ID
+		 * @param[in] version PPPoE version
+		 * @param[in] type PPPoE type
+		 * @param[in] sessionId PPPoE session ID
+		 * @param[in] pppNextProtocol The next protocol to come after the PPPoE session header. Should be one of the PPP_* macros listed below
+		 */
+		PPPoESessionLayer(uint8_t version, uint8_t type, uint16_t sessionId, uint16_t pppNextProtocol) : PPPoELayer(version, type, PPPoELayer::PPPOE_CODE_SESSION, sessionId, sizeof(uint16_t)) { setPPPNextProtocol(pppNextProtocol); }
+
+		virtual ~PPPoESessionLayer() {}
+
+		/**
+		 * @return The protocol after the PPPoE session header. The return value is one of the PPP_* macros listed below. This method is also
+		 * used when parsing a packet (this way we know which layer comes after the PPPoE session)
+		 */
+		uint16_t getPPPNextProtocol();
+
+		/**
+		 * Set the field that describes which header comes after the PPPoE session header
+		 * @param[in] nextProtocol The protocol value. Should be one of the PPP_* macros listed below
+		 */
+		void setPPPNextProtocol(uint16_t nextProtocol);
+
+		// abstract methods implementation
+
+		/**
+		 * Currently identifies the following next layers: IPv4Layer, IPv6Layer. Otherwise sets PayloadLayer
+		 */
+		virtual void parseNextLayer();
+
+		/**
+		 * @return Size of @ref pppoe_header
+		 */
+		virtual size_t getHeaderLen() { return sizeof(pppoe_header) + sizeof(uint16_t); }
+
+		virtual std::string toString();
+	};
+
+
+
+	/**
+	 * @class PPPoEDiscoveryLayer
+	 * Describes the PPPoE discovery protocol
+	 */
+	class PPPoEDiscoveryLayer : public PPPoELayer
+	{
+	public:
+		/**
+		 * PPPoE tag types
+		 */
+		enum PPPoETagTypes
+		{
+			/** End-Of-List tag type*/
+			PPPOE_TAG_EOL		 = 0x0000,
+			/** Service-Name tag type*/
+			PPPOE_TAG_SVC_NAME	 = 0x0101,
+			/** AC-Name tag type*/
+			PPPOE_TAG_AC_NAME	 = 0x0102,
+			/** Host-Uniq tag type*/
+			PPPOE_TAG_HOST_UNIQ	 = 0x0103,
+			/** AC-Cookie tag type*/
+			PPPOE_TAG_AC_COOKIE	 = 0x0104,
+			/** Vendor-Specific tag type*/
+			PPPOE_TAG_VENDOR	 = 0x0105,
+			/** Credits tag type*/
+			PPPOE_TAG_CREDITS	 = 0x0106,
+			/** Metrics tag type*/
+			PPPOE_TAG_METRICS	 = 0x0107,
+			/** Sequence Number tag type */
+			PPPOE_TAG_SEQ_NUM	 = 0x0108,
+			/** Credit Scale Factor tag type */
+			PPPOE_TAG_CRED_SCALE = 0x0109,
+			/** Relay-Session-Id tag type */
+			PPPOE_TAG_RELAY_ID	 = 0x0110,
+			/** HURL tag type */
+			PPPOE_TAG_HURL		 = 0x0111,
+			/** MOTM tag type */
+			PPPOE_TAG_MOTM		 = 0x0112,
+			/** PPP-Max-Payload tag type */
+			PPPOE_TAG_MAX_PAYLD	 = 0x0120,
+			/** IP_Route_Add tag type */
+			PPPOE_TAG_IP_RT_ADD	 = 0x0121,
+			/** Service-Name-Error tag type */
+			PPPOE_TAG_SVC_ERR	 = 0x0201,
+			/** AC-System-Error tag type */
+			PPPOE_TAG_AC_ERR	 = 0x0202,
+			/** Generic-Error tag type */
+			PPPOE_TAG_GENERIC_ERR= 0x0203
+		};
+
+		/**
+		 * @struct PPPoETag
+		 * Represents a PPPoE tag and its data
+		 */
+		struct PPPoETag
+		{
+		public:
+
+			/** The type of the data, can be converted to PPPoEDiscoveryLayer#PPPoETagTypes enum (or use getType()) */
+			uint16_t tagType;
+			/** The length of the tag data */
+			uint16_t tagDataLength;
+			/** A pointer to the tag data. It's recommended to use getTagDataAs() to retrieve the tag data or setTagData() to set tag data */
+			uint8_t	 tagData[];
+
+			/**
+			 * A templated method to retrieve the tag data as a certain type T. For example, if tag data is 4B (integer) then this method
+			 * should be used as getTagDataAs<int>() and it will return the tag data as integer.<BR>
+			 * Notice this return value is a copy of the data, not a pointer to the actual data
+			 * @param[in] tagDataOffset An optional parameter that specifies where to start copy the tag data. For example: if tag data is 20 bytes
+			 * and you need only the 4 last bytes as integer then use this method like this: getTagDataAs<int>(16). The default is 0 - start copy
+			 * from the beginning of tag data
+			 * @return The tag data as type T
+			 */
+			template<typename T>
+			T getTagDataAs(int tagDataOffset = 0)
+			{
+				T result;
+				memcpy(&result, tagData+tagDataOffset, sizeof(T));
+				return result;
+			}
+
+			/**
+			 * A templated method to copy data of type T into the tag data. For example: if tag data is 4[Bytes] long use this method like
+			 * this to set an integer "num" into tag data: setTagData<int>(num)
+			 * @param[in] value The value of type T to copy to tag data
+			 * @param[in] tagDataOffset An optional parameter that specifies where to start set the tag data. For example: if tag data is 20 bytes
+			 * and you only need to set the 4 last bytes as integer then use this method like this: setTagDataAs<int>(num, 16).
+			 * The default is 0 - start copy to the beginning of tag data
+			 */
+			template<typename T>
+			void setTagData(T value, int tagDataOffset = 0)
+			{
+				memcpy(tagData+tagDataOffset, &value, sizeof(T));
+			}
+
+			/**
+			 * @return The total size in bytes of this tag which includes: 2[Bytes] (tag name) + 2[Bytes] (tag length) + X[Bytes] (tag data length)
+			 */
+			size_t getTagTotalSize() const;
+
+			/**
+			 * @return The tag type converted to PPPoEDiscoveryLayer#PPPoETagTypes enum
+			 */
+			PPPoEDiscoveryLayer::PPPoETagTypes getType();
+		private:
+			// private c'tor which isn't implemented to make this struct impossible to construct
+			PPPoETag();
+		};
+
+		/**
+		 * A constructor that creates the layer from an existing packet raw data
+		 * @param[in] data A pointer to the raw data (will be casted to @ref pppoe_header)
+		 * @param[in] dataLen Size of the data in bytes
+		 * @param[in] prevLayer A pointer to the previous layer
+		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
+		 */
+		PPPoEDiscoveryLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : PPPoELayer(data, dataLen, prevLayer, packet) { m_Protocol = PPPoEDiscovery; m_TagCount = -1; }
+
+		/**
+		 * A constructor that allocates a new PPPoE Discovery header with version, type, PPPoE code and session ID
+		 * @param[in] version PPPoE version
+		 * @param[in] type PPPoE type
+		 * @param[in] code PPPoE code enum
+		 * @param[in] sessionId PPPoE session ID
+		 */
+		PPPoEDiscoveryLayer(uint8_t version, uint8_t type, PPPoELayer::PPPoECode code, uint16_t sessionId) : PPPoELayer(version, type, code, sessionId) { m_Protocol = PPPoEDiscovery; m_TagCount = -1; }
+
+		/**
+		 * A copy constructor that copies the entire header from the other PPPoEDiscoveryLayer
+		 */
+		PPPoEDiscoveryLayer(const PPPoEDiscoveryLayer& other) : PPPoELayer(other) { m_TagCount = other.m_TagCount; }
+
+		/**
+		 * Retrieve a PPPoE tag by tag type. If packet consists of multiple tags of the same type, the first tag will be returned. If packet contains
+		 * no tags of the tag type NULL will be returned. Notice the return value is a pointer to the real data casted to PPPoETag type (as opposed
+		 * to a copy of the tag data). So changes in the return value will affect the packet data
+		 * @param[in] tagType The type of the tag to search
+		 * @return A pointer to the tag data casted to PPPoETag*
+		 */
+		PPPoETag* getTag(PPPoEDiscoveryLayer::PPPoETagTypes tagType);
+
+		/**
+		 * @return The first tag in the PPPoE discovery layer, or NULL if no tags exist. Notice the return value is a pointer to the real data casted to PPPoETag type (as opposed
+		 * to a copy of the tag data). So changes in the return value will affect the packet data
+		 */
+		PPPoETag* getFirstTag();
+
+		/**
+		 * Get the tag which come next to "tag" parameter. If "tag" is NULL or then NULL will be returned. If "tag" is the last tag NULL will be
+		 * returned. Notice the return value is a pointer to the real data casted to PPPoETag type (as opposed to a copy of the tag data).
+		 * So changes in the return value will affect the packet data
+		 * @param[in] tag The tag to start search
+		 * @return The next tag or NULL if "tag" is NULL or "tag" is the last tag
+		 */
+		PPPoETag* getNextTag(PPPoETag* tag);
+
+		/**
+		 * @return The number of tags in this layer
+		 */
+		int getTagCount();
+
+		/**
+		 * Add a new tag at the end of the layer (after the last tag)
+		 * @param[in] tagType The type of the added tag
+		 * @param[in] tagLength The length of the tag data
+		 * @param[in] tagData A pointer to the tag data. This data will be copied to added tag data. Notice the length of tagData must be tagLength
+		 * @return A pointer to the new added tag. Notice this is a pointer to the real data casted to PPPoETag type (as opposed to a copy of
+		 * the tag data). So changes in this return value will affect the packet data
+		 */
+		PPPoETag* addTag(PPPoETagTypes tagType, uint16_t tagLength, const uint8_t* tagData);
+
+		/**
+		 * Add a new tag after an existing tag
+		 * @param[in] tagType The type of the added tag
+		 * @param[in] tagLength The length of the tag data
+		 * @param[in] tagData A pointer to the tag data. This data will be copied to added tag data. Notice the length of tagData must be tagLength
+		 * @param[in] prevTag The tag which the new added tag will come after
+		 * @return A pointer to the new added tag. Notice this is a pointer to the real data casted to PPPoETag type (as opposed to a copy of
+		 * the tag data). So changes in this return value will affect the packet data
+		 */
+		PPPoETag* addTagAfter(PPPoETagTypes tagType, uint16_t tagLength, const uint8_t* tagData, PPPoETag* prevTag);
+
+		/**
+		 * Remove an existing tag. Tag will be found by the tag type
+		 * @param[in] tagType The tag type to remove
+		 * @return True if tag was removed or false if tag wasn't found or if tag removal failed (in each case a proper error will be written
+		 * to log)
+		 */
+		bool removeTag(PPPoEDiscoveryLayer::PPPoETagTypes tagType);
+
+		/**
+		 * Remove all tags in this layer
+		 * @return True if all tags were successfully or false if removal failed for some reason (a proper error will be written to log)
+		 */
+		bool removeAllTags();
+
+		// abstract methods implementation
+
+		/**
+		 * Does nothing for this layer (PPPoE discovery is always the last layer)
+		 */
+		virtual void parseNextLayer() {};
+
+		/**
+		 * @return The header length which is size of strcut pppoe_header plus the total size of tags
+		 */
+		virtual size_t getHeaderLen();
+
+		virtual std::string toString() { return "PPP-over-Ethernet Discovery (" + codeToString((PPPoELayer::PPPoECode)getPPPoEHeader()->code) + ")"; }
+
+	private:
+		int m_TagCount;
+
+		PPPoETag* addTagAt(PPPoETagTypes tagType, uint16_t tagLength, const uint8_t* tagData, int offset);
+
+		PPPoETag* castPtrToPPPoETag(uint8_t* ptr);
+
+		std::string codeToString(PPPoECode code);
+	};
+
+
+	// Copied from Wireshark: ppptypes.h
+
+	/** Padding Protocol */
+#define PCPP_PPP_PADDING		0x1
+	/** ROHC small-CID */
+#define PCPP_PPP_ROHC_SCID		0x3
+	/** ROHC large-CID */
+#define PCPP_PPP_ROHC_LCID		0x5
+	/** Internet Protocol version 4 */
+#define PCPP_PPP_IP				0x21
+	/** OSI Network Layer */
+#define PCPP_PPP_OSI			0x23
+	/** Xerox NS IDP */
+#define PCPP_PPP_XNSIDP			0x25
+	/** DECnet Phase IV */
+#define PCPP_PPP_DEC4			0x27
+	/** AppleTalk */
+#define PCPP_PPP_AT				0x29
+	/** Novell IPX */
+#define PCPP_PPP_IPX			0x2b
+	/** Van Jacobson Compressed TCP/IP */
+#define PCPP_PPP_VJC_COMP		0x2d
+	/** Van Jacobson Uncompressed TCP/IP */
+#define PCPP_PPP_VJC_UNCOMP		0x2f
+	/** Bridging PDU */
+#define PCPP_PPP_BCP			0x31
+	/** Stream Protocol (ST-II) */
+#define PCPP_PPP_ST				0x33
+	/** Banyan Vines */
+#define PCPP_PPP_VINES			0x35
+	/** AppleTalk EDDP */
+#define PCPP_PPP_AT_EDDP		0x39
+	/** AppleTalk SmartBuffered */
+#define PCPP_PPP_AT_SB			0x3b
+	/** Multi-Link */
+#define PCPP_PPP_MP				0x3d
+	/** NETBIOS Framing */
+#define PCPP_PPP_NB				0x3f
+	/** Cisco Systems */
+#define PCPP_PPP_CISCO			0x41
+	/** Ascom Timeplex */
+#define PCPP_PPP_ASCOM			0x43
+	/** Fujitsu Link Backup and Load Balancing */
+#define PCPP_PPP_LBLB			0x45
+	/** DCA Remote Lan */
+#define PCPP_PPP_RL				0x47
+	/** Serial Data Transport Protocol */
+#define PCPP_PPP_SDTP			0x49
+	/** SNA over 802.2 */
+#define PCPP_PPP_LLC			0x4b
+	/** SNA */
+#define PCPP_PPP_SNA			0x4d
+	/** IPv6 Header Compression  */
+#define PCPP_PPP_IPV6HC			0x4f
+	/** KNX Bridging Data */
+#define PCPP_PPP_KNX			0x51
+	/** Encryption */
+#define PCPP_PPP_ENCRYPT		0x53
+	/** Individual Link Encryption */
+#define PCPP_PPP_ILE			0x55
+	/** Internet Protocol version 6 */
+#define PCPP_PPP_IPV6			0x57
+	/** PPP Muxing */
+#define PCPP_PPP_MUX			0x59
+	/** Vendor-Specific Network Protocol (VSNP) */
+#define PCPP_PPP_VSNP			0x5b
+	/** TRILL Network Protocol (TNP) */
+#define PCPP_PPP_TNP			0x5d
+	/** RTP IPHC Full Header */
+#define PCPP_PPP_RTP_FH			0x61
+	/** RTP IPHC Compressed TCP */
+#define PCPP_PPP_RTP_CTCP		0x63
+	/** RTP IPHC Compressed Non TCP */
+#define PCPP_PPP_RTP_CNTCP		0x65
+	/** RTP IPHC Compressed UDP 8 */
+#define PCPP_PPP_RTP_CUDP8		0x67
+	/** RTP IPHC Compressed RTP 8 */
+#define PCPP_PPP_RTP_CRTP8		0x69
+	/** Stampede Bridging */
+#define PCPP_PPP_STAMPEDE		0x6f
+	/** MP+ Protocol */
+#define PCPP_PPP_MPPLUS			0x73
+	/** NTCITS IPI */
+#define PCPP_PPP_NTCITS_IPI		0xc1
+	/** Single link compression in multilink */
+#define PCPP_PPP_ML_SLCOMP		0xfb
+	/** Compressed datagram */
+#define PCPP_PPP_COMP			0xfd
+	/** 802.1d Hello Packets */
+#define PCPP_PPP_STP_HELLO		0x0201
+	/** IBM Source Routing BPDU */
+#define PCPP_PPP_IBM_SR			0x0203
+	/** DEC LANBridge100 Spanning Tree */
+#define PCPP_PPP_DEC_LB			0x0205
+	/** Cisco Discovery Protocol */
+#define PCPP_PPP_CDP			0x0207
+	/** Netcs Twin Routing */
+#define PCPP_PPP_NETCS			0x0209
+	/** STP - Scheduled Transfer Protocol */
+#define PCPP_PPP_STP			0x020b
+	/** EDP - Extreme Discovery Protocol */
+#define PCPP_PPP_EDP			0x020d
+	/** Optical Supervisory Channel Protocol */
+#define PCPP_PPP_OSCP			0x0211
+	/** Optical Supervisory Channel Protocol */
+#define PCPP_PPP_OSCP2			0x0213
+	/** Luxcom */
+#define PCPP_PPP_LUXCOM			0x0231
+	/** Sigma Network Systems */
+#define PCPP_PPP_SIGMA			0x0233
+	/** Apple Client Server Protocol */
+#define PCPP_PPP_ACSP			0x0235
+	/** MPLS Unicast */
+#define PCPP_PPP_MPLS_UNI		0x0281
+	/** MPLS Multicast */
+#define PCPP_PPP_MPLS_MULTI		0x0283
+	/** IEEE p1284.4 standard - data packets */
+#define PCPP_PPP_P12844			0x0285
+	/** ETSI TETRA Network Procotol Type 1 */
+#define PCPP_PPP_TETRA			0x0287
+	/** Multichannel Flow Treatment Protocol */
+#define PCPP_PPP_MFTP			0x0289
+	/** RTP IPHC Compressed TCP No Delta */
+#define PCPP_PPP_RTP_CTCPND		0x2063
+	/** RTP IPHC Context State */
+#define PCPP_PPP_RTP_CS			0x2065
+	/** RTP IPHC Compressed UDP 16 */
+#define PCPP_PPP_RTP_CUDP16		0x2067
+	/** RTP IPHC Compressed RTP 16 */
+#define PCPP_PPP_RTP_CRDP16		0x2069
+	/** Cray Communications Control Protocol */
+#define PCPP_PPP_CCCP			0x4001
+	/** CDPD Mobile Network Registration Protocol */
+#define PCPP_PPP_CDPD_MNRP		0x4003
+	/** Expand accelerator protocol */
+#define PCPP_PPP_EXPANDAP		0x4005
+	/** ODSICP NCP */
+#define PCPP_PPP_ODSICP			0x4007
+	/** DOCSIS DLL */
+#define PCPP_PPP_DOCSIS			0x4009
+	/** Cetacean Network Detection Protocol */
+#define PCPP_PPP_CETACEANNDP	0x400b
+	/** Stacker LZS */
+#define PCPP_PPP_LZS			0x4021
+	/** RefTek Protocol */
+#define PCPP_PPP_REFTEK			0x4023
+	/** Fibre Channel */
+#define PCPP_PPP_FC				0x4025
+	/** EMIT Protocols */
+#define PCPP_PPP_EMIT			0x4027
+	/** Vendor-Specific Protocol (VSP) */
+#define PCPP_PPP_VSP			0x405b
+	/** TRILL Link State Protocol (TLSP) */
+#define PCPP_PPP_TLSP			0x405d
+	/** Internet Protocol Control Protocol */
+#define PCPP_PPP_IPCP			0x8021
+	/** OSI Network Layer Control Protocol */
+#define PCPP_PPP_OSINLCP		0x8023
+	/** Xerox NS IDP Control Protocol */
+#define PCPP_PPP_XNSIDPCP		0x8025
+	/** DECnet Phase IV Control Protocol */
+#define PCPP_PPP_DECNETCP		0x8027
+	/** AppleTalk Control Protocol */
+#define PCPP_PPP_ATCP			0x8029
+	/** Novell IPX Control Protocol */
+#define PCPP_PPP_IPXCP			0x802b
+	/** Bridging NCP */
+#define PCPP_PPP_BRIDGENCP		0x8031
+	/** Stream Protocol Control Protocol */
+#define PCPP_PPP_SPCP			0x8033
+	/** Banyan Vines Control Protocol */
+#define PCPP_PPP_BVCP			0x8035
+	/** Multi-Link Control Protocol */
+#define PCPP_PPP_MLCP			0x803d
+	/** NETBIOS Framing Control Protocol */
+#define PCPP_PPP_NBCP			0x803f
+	/** Cisco Systems Control Protocol */
+#define PCPP_PPP_CISCOCP		0x8041
+	/** Ascom Timeplex Control Protocol (?) */
+#define PCPP_PPP_ASCOMCP		0x8043
+	/** Fujitsu LBLB Control Protocol */
+#define PCPP_PPP_LBLBCP			0x8045
+	/** DCA Remote Lan Network Control Protocol */
+#define PCPP_PPP_RLNCP			0x8047
+	/** Serial Data Control Protocol */
+#define PCPP_PPP_SDCP			0x8049
+	/** SNA over 802.2 Control Protocol */
+#define PCPP_PPP_LLCCP			0x804b
+	/** SNA Control Protocol */
+#define PCPP_PPP_SNACP			0x804d
+	/** IP6 Header Compression Control Protocol */
+#define PCPP_PPP_IP6HCCP		0x804f
+	/** KNX Bridging Control Protocol */
+#define PCPP_PPP_KNXCP			0x8051
+	/** Encryption Control Protocol */
+#define PCPP_PPP_ECP			0x8053
+	/** Individual Link Encryption Control Protocol */
+#define PCPP_PPP_ILECP			0x8055
+	/** IPv6 Control Protocol */
+#define PCPP_PPP_IPV6CP			0x8057
+	/** PPP Muxing Control Protocol */
+#define PCPP_PPP_MUXCP			0x8059
+	/** Vendor-Specific Network Control Protocol (VSNCP)   [RFC3772] */
+#define PCPP_PPP_VSNCP			0x805b
+	/** TRILL Network Control Protocol (TNCP) */
+#define PCPP_PPP_TNCP			0x805d
+	/** Stampede Bridging Control Protocol */
+#define PCPP_PPP_STAMPEDECP		0x806f
+	/** MP+ Contorol Protocol */
+#define PCPP_PPP_MPPCP			0x8073
+	/** NTCITS IPI Control Protocol */
+#define PCPP_PPP_IPICP			0x80c1
+	/** Single link compression in multilink control */
+#define PCPP_PPP_SLCC			0x80fb
+	/** Compression Control Protocol */
+#define PCPP_PPP_CCP			0x80fd
+	/** Cisco Discovery Protocol Control Protocol */
+#define PCPP_PPP_CDPCP			0x8207
+	/** Netcs Twin Routing */
+#define PCPP_PPP_NETCSCP		0x8209
+	/** STP - Control Protocol */
+#define PCPP_PPP_STPCP			0x820b
+	/** EDPCP - Extreme Discovery Protocol Control Protocol */
+#define PCPP_PPP_EDPCP			0x820d
+	/** Apple Client Server Protocol Control */
+#define PCPP_PPP_ACSPC			0x8235
+	/** MPLS Control Protocol */
+#define PCPP_PPP_MPLSCP			0x8281
+	/** IEEE p1284.4 standard - Protocol Control */
+#define PCPP_PPP_P12844CP		0x8285
+	/** ETSI TETRA TNP1 Control Protocol */
+#define PCPP_PPP_TETRACP		0x8287
+	/** Multichannel Flow Treatment Protocol */
+#define PCPP_PPP_MFTPCP			0x8289
+	/** Link Control Protocol */
+#define PCPP_PPP_LCP			0xc021
+	/** Password Authentication Protocol */
+#define PCPP_PPP_PAP			0xc023
+	/** Link Quality Report */
+#define PCPP_PPP_LQR			0xc025
+	/** Shiva Password Authentication Protocol */
+#define PCPP_PPP_SPAP			0xc027
+	/** CallBack Control Protocol (CBCP) */
+#define PCPP_PPP_CBCP			0xc029
+	/** BACP Bandwidth Allocation Control Protocol */
+#define PCPP_PPP_BACP			0xc02b
+	/** BAP Bandwidth Allocation Protocol */
+#define PCPP_PPP_BAP			0xc02d
+	/** Vendor-Specific Authentication Protocol (VSAP) */
+#define PCPP_PPP_VSAP			0xc05b
+	/** Container Control Protocol */
+#define PCPP_PPP_CONTCP			0xc081
+	/** Challenge Handshake Authentication Protocol */
+#define PCPP_PPP_CHAP			0xc223
+	/** RSA Authentication Protocol */
+#define PCPP_PPP_RSAAP			0xc225
+	/** Extensible Authentication Protocol */
+#define PCPP_PPP_EAP			0xc227
+	/** Mitsubishi Security Information Exchange Protocol (SIEP) */
+#define PCPP_PPP_SIEP			0xc229
+	/** Stampede Bridging Authorization Protocol */
+#define PCPP_PPP_SBAP			0xc26f
+	/** Proprietary Authentication Protocol */
+#define PCPP_PPP_PRPAP			0xc281
+	/** Proprietary Authentication Protocol */
+#define PCPP_PPP_PRPAP2			0xc283
+	/** Proprietary Node ID Authentication Protocol */
+#define PCPP_PPP_PRPNIAP		0xc481
+
+} // namespace pcpp
+
+#endif /* PACKETPP_PPPOE_LAYER */