// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // Copyright (c) 2001-2008 XORP, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software") // to deal in the Software without restriction, subject to the conditions // listed in the XORP LICENSE file. These conditions include: you must // preserve this copyright notice, and you cannot mention the copyright // holders in advertising related to the Software without their permission. // The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This // notice is a summary of the XORP LICENSE file; the license in that file is // legally binding. // $XORP: xorp/libproto/packet.hh,v 1.13 2008/07/23 05:10:39 pavlin Exp $ #ifndef __LIBPROTO_PACKET_HH__ #define __LIBPROTO_PACKET_HH__ #include "libxorp/xorp.h" #include "libxorp/ipv4.hh" #include "libxorp/ipv6.hh" /** * Extract an 8-bit number from the beginning of a buffer. * * Note that the integers in the buffer are stored in network order. * * @param ptr the buffer with the data. * @return an 8-bit number from the beginning of a buffer. */ inline uint8_t extract_8(const uint8_t *ptr) { uint8_t val; val = ptr[0]; return val; } /** * Embed an 8-bit number into the beginning of a buffer. * * Note that the integers in the buffer are stored in network order. * * @param ptr the buffer to store the data. * @param val the 8-bit value to embed into the beginning of the buffer. */ inline void embed_8(uint8_t *ptr, uint8_t val) { ptr[0] = val; } /** * Extract a 16-bit number from the beginning of a buffer. * * Note that the integers in the buffer are stored in network order. * * @param ptr the buffer with the data. * @return a 16-bit number from the beginning of a buffer. */ inline uint16_t extract_16(const uint8_t *ptr) { uint16_t val; val = ptr[0]; val <<= 8; val |= ptr[1]; return val; } /** * Embed a 16-bit number into the beginning of a buffer. * * Note that the integers in the buffer are stored in network order. * * @param ptr the buffer to store the data. * @param val the 16-bit value to embed into the beginning of the buffer. */ inline void embed_16(uint8_t *ptr, uint16_t val) { ptr[0] = (val >> 8) & 0xff; ptr[1] = val & 0xff; } /** * Extract a 24-bit number from the beginning of a buffer. * * Note that the integers in the buffer are stored in network order. * * @param ptr the buffer with the data. * @return a 24-bit number from the beginning of a buffer. */ inline uint32_t extract_24(const uint8_t *ptr) { uint32_t val; val = ptr[0]; val <<= 8; val |= ptr[1]; val <<= 8; val |= ptr[2]; return val; } /** * Embed a 24-bit number into the beginning of a buffer. * * Note that the integers in the buffer are stored in network order. * * @param ptr the buffer to store the data. * @param val the 24-bit value to embed into the beginning of the buffer. */ inline void embed_24(uint8_t *ptr, uint32_t val) { ptr[0] = (val >> 16) & 0xff; ptr[1] = (val >> 8) & 0xff; ptr[2] = val & 0xff; } /** * Extract a 32-bit number from the beginning of a buffer. * * Note that the integers in the buffer are stored in network order. * * @param ptr the buffer with the data. * @return a 32-bit number from the beginning of a buffer. */ inline uint32_t extract_32(const uint8_t *ptr) { uint32_t val; val = ptr[0]; val <<= 8; val |= ptr[1]; val <<= 8; val |= ptr[2]; val <<= 8; val |= ptr[3]; return val; } /** * Embed a 32-bit number into the beginning of a buffer. * * Note that the integers in the buffer are stored in network order. * * @param ptr the buffer to store the data. * @param val the 32-bit value to embed into the beginning of the buffer. */ inline void embed_32(uint8_t *ptr, uint32_t val) { ptr[0] = (val >> 24) & 0xff; ptr[1] = (val >> 16) & 0xff; ptr[2] = (val >> 8) & 0xff; ptr[3] = val & 0xff; } /** * Extract an 8-bit number from the beginning of a buffer. * * Note that the integers in the buffer are stored in host order. * * @param ptr the buffer with the data. * @return an 8-bit number from the beginning of a buffer. */ inline uint8_t extract_host_8(const uint8_t *ptr) { uint8_t val; val = ptr[0]; return val; } /** * Embed an 8-bit number into the beginning of a buffer. * * Note that the integers in the buffer are stored in host order. * * @param ptr the buffer to store the data. * @param val the 8-bit value to embed into the beginning of the buffer. */ inline void embed_host_8(uint8_t *ptr, uint8_t val) { ptr[0] = val; } /** * Extract a 16-bit number from the beginning of a buffer. * * Note that the integers in the buffer are stored in host order. * * @param ptr the buffer with the data. * @return a 16-bit number from the beginning of a buffer. */ inline uint16_t extract_host_16(const uint8_t *ptr) { union { uint16_t val; uint8_t c[sizeof(uint16_t)]; } u; u.c[0] = ptr[0]; u.c[1] = ptr[1]; return u.val; } /** * Embed a 16-bit number into the beginning of a buffer. * * Note that the integers in the buffer are stored in host order. * * @param ptr the buffer to store the data. * @param val the 16-bit value to embed into the beginning of the buffer. */ inline void embed_host_16(uint8_t *ptr, uint16_t val) { union { uint16_t val; uint8_t c[sizeof(uint16_t)]; } u; u.val = val; ptr[0] = u.c[0]; ptr[1] = u.c[1]; } /* * XXX: Note that we don't define extract_host_24() and embed_host_24(), * because 3 octets of data might occupy either 3 or 4 octets (depending * on the byte ordering). Hence, extract_host_32() and embed_host_32() * should be used instead. */ /** * Extract a 32-bit number from the beginning of a buffer. * * Note that the integers in the buffer are stored in host order. * * @param ptr the buffer with the data. * @return a 32-bit number from the beginning of a buffer. */ inline uint32_t extract_host_32(const uint8_t *ptr) { union { uint32_t val; uint8_t c[sizeof(uint32_t)]; } u; u.c[0] = ptr[0]; u.c[1] = ptr[1]; u.c[2] = ptr[2]; u.c[3] = ptr[3]; return u.val; } /** * Embed a 32-bit number into the beginning of a buffer. * * Note that the integers in the buffer are stored in host order. * * @param ptr the buffer to store the data. * @param val the 32-bit value to embed into the beginning of the buffer. */ inline void embed_host_32(uint8_t *ptr, uint32_t val) { union { uint32_t val; uint8_t c[sizeof(uint32_t)]; } u; u.val = val; ptr[0] = u.c[0]; ptr[1] = u.c[1]; ptr[2] = u.c[2]; ptr[3] = u.c[3]; } /** * Extract an integer number from the beginning of a buffer. * * Note that the integers in the buffer are stored in host order. * * @param ptr the buffer with the data. * @return an integer number from the beginning of a buffer. */ inline int extract_host_int(const uint8_t *ptr) { union { int val; uint8_t c[sizeof(int)]; } u; for (size_t i = 0; i < sizeof(int); i++) { u.c[i] = ptr[i]; } return u.val; } /** * Embed an integer number into the beginning of a buffer. * * Note that the integers in the buffer are stored in host order. * * @param ptr the buffer to store the data. * @param val the integer value to embed into the beginning of the buffer. */ inline void embed_host_int(uint8_t *ptr, int val) { union { int val; uint8_t c[sizeof(int)]; } u; u.val = val; for (size_t i = 0; i < sizeof(int); i++) { ptr[i] = u.c[i]; } } /** * @short IPv4 packet header. * * The IPv4 packet header has the following content: * * ip_vhl (1 byte): // IP ver/hdrlen (version << 4 | header length >> 2) * ip_tos (1 byte): // Type of service * ip_len (2 bytes): // Total length * ip_id (2 bytes): // Identification * ip_off (2 bytes): // Fragment offset field (least-significant 13 bits) * ip_ttl (1 byte): // Time to live * ip_p (1 byte): // Protocol * ip_sum (2 bytes): // Checksum * ip_src (4 bytes): // Source address * ip_dst (4 bytes): // Destination address */ class IpHeader4 { public: IpHeader4(const uint8_t* data) : _data(data), _ip_vhl(_data + _ip_vhl_offset), _ip_tos(_data + _ip_tos_offset), _ip_len(_data + _ip_len_offset), _ip_id(_data + _ip_id_offset), _ip_off(_data + _ip_off_offset), _ip_ttl(_data + _ip_ttl_offset), _ip_p(_data + _ip_p_offset), _ip_sum(_data + _ip_sum_offset), _ip_src(_data + _ip_src_offset), _ip_dst(_data + _ip_dst_offset) { static_assert(IpHeader4::SIZE == _ip_vhl_sizeof + _ip_tos_sizeof + _ip_len_sizeof + _ip_id_sizeof + _ip_off_sizeof + _ip_ttl_sizeof + _ip_p_sizeof + _ip_sum_sizeof + _ip_src_sizeof + _ip_dst_sizeof); static_assert(IpHeader4::SIZE == _ip_dst_offset + _ip_dst_sizeof); } static const size_t SIZE = 20; // The header size static const uint8_t IP_VERSION = 4; // IPv4 version /** * Get the IPv4 packet header size. * * Note that this is the header size only without any header options. * * @return the IPv4 packet header size. */ static size_t size() { return IpHeader4::SIZE; } /** * Get the buffer data. * * @return the buffer data. */ const uint8_t* data() const { return (_data); } /** * Methods to get various IP header fields. */ uint8_t ip_vhl() const { return extract_8(_ip_vhl); } uint8_t ip_tos() const { return extract_8(_ip_tos); } uint16_t ip_len() const { return extract_16(_ip_len); } uint16_t ip_id() const { return extract_16(_ip_id); } uint16_t ip_off() const { return extract_16(_ip_off); } uint8_t ip_ttl() const { return extract_8(_ip_ttl); } uint8_t ip_p() const { return extract_8(_ip_p); } uint16_t ip_sum() const { return extract_16(_ip_sum); } IPv4 ip_src() const { return IPv4(_ip_src); } IPv4 ip_dst() const { return IPv4(_ip_dst); } /* * A method to extract the ip_len value that is presumably stored * in host order. * * @return the ip_len value that is presumably stored in host order. */ uint16_t ip_len_host() const{ return extract_host_16(_ip_len); } /** * Get the IP protocol version of the header. * * @return the IP protocol version of the header. */ uint8_t ip_version() const { uint8_t v = ip_vhl(); return ((v >> 4) & 0x0f); } /** * Get the IPv4 packet header size (including any header options). * * @return the IPv4 packet header size (including any header options). */ uint8_t ip_header_len() const { return ((ip_vhl() & 0x0f) << 2); } /** * Get the IPv4 fragment offset (excluding the fragment flags). * * @return the IPv4 fragment offset (excluding the fragment flags). */ uint16_t ip_fragment_offset() const { return (ip_off() & IpHeader4::FRAGMENT_OFFSET_MASK); } /** * Get the IPv4 fragment flags. * * @return the IPv4 fragment flags. */ uint16_t ip_fragment_flags() const { return (ip_off() & IpHeader4::FRAGMENT_FLAGS_MASK); } /** * Test whether the IP header version is valid. * * @return true if the IP header version is valid, otherwise false. */ bool is_valid_version() const { return (ip_version() == IpHeader4::IP_VERSION); } /** * Fragment an IPv4 packet. * * Note: If the original packet is not larger than the MTU, then the packet * is not fragmented (i.e., @ref fragments is empty), and the return * value is XORP_OK. * * @param mtu the MTU for fragmenting the packet. * @param fragments the return-by-reference fragments of the IPv4 packet. * @param do_checksum if true, compute and set the checksum in the IPv4 * header, otherwise reset it to zero. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int fragment(size_t mtu, list<vector<uint8_t> >& fragments, bool do_checksum, string& error_msg) const; protected: // IPv4 header related constants static const uint16_t FRAGMENT_OFFSET_MASK = 0x1fff; static const uint16_t FRAGMENT_FLAGS_MASK = 0xe000; static const uint16_t FRAGMENT_FLAGS_IP_DF = 0x4000; // Don't fragment static const uint16_t FRAGMENT_FLAGS_IP_MF = 0x2000; // More fragments static const uint8_t OPTIONS_IPOPT_EOL = 0; // End of option list static const uint8_t OPTIONS_IPOPT_NOP = 1; // No operation static const size_t OPTIONS_IPOPT_OLEN = 1; // Option length offset static const uint8_t OPTIONS_COPIED_FLAG = 0x80; // Option copied flag // Sizes of the fields static const size_t _ip_vhl_sizeof = 1; static const size_t _ip_tos_sizeof = 1; static const size_t _ip_len_sizeof = 2; static const size_t _ip_id_sizeof = 2; static const size_t _ip_off_sizeof = 2; static const size_t _ip_ttl_sizeof = 1; static const size_t _ip_p_sizeof = 1; static const size_t _ip_sum_sizeof = 2; static const size_t _ip_src_sizeof = 4; static const size_t _ip_dst_sizeof = 4; // Offsets for the fields static const size_t _ip_vhl_offset = 0; static const size_t _ip_tos_offset = _ip_vhl_offset + _ip_vhl_sizeof; static const size_t _ip_len_offset = _ip_tos_offset + _ip_tos_sizeof; static const size_t _ip_id_offset = _ip_len_offset + _ip_len_sizeof; static const size_t _ip_off_offset = _ip_id_offset + _ip_id_sizeof; static const size_t _ip_ttl_offset = _ip_off_offset + _ip_off_sizeof; static const size_t _ip_p_offset = _ip_ttl_offset + _ip_ttl_sizeof; static const size_t _ip_sum_offset = _ip_p_offset + _ip_p_sizeof; static const size_t _ip_src_offset = _ip_sum_offset + _ip_sum_sizeof; static const size_t _ip_dst_offset = _ip_src_offset + _ip_src_sizeof; private: const uint8_t* _data; // The buffer data // Pointers to the fields const uint8_t* _ip_vhl; // IP version and header length const uint8_t* _ip_tos; // Type of service const uint8_t* _ip_len; // Total length const uint8_t* _ip_id; // Identification const uint8_t* _ip_off; // Fragment offset field const uint8_t* _ip_ttl; // Time to live const uint8_t* _ip_p; // Protocol const uint8_t* _ip_sum; // Checksum const uint8_t* _ip_src; // Source address const uint8_t* _ip_dst; // Destination address }; /** * @short Class for writing data to IPv4 packet header. */ class IpHeader4Writer : public IpHeader4 { public: IpHeader4Writer(uint8_t* data) : IpHeader4(data), _data(data), _ip_vhl(_data + _ip_vhl_offset), _ip_tos(_data + _ip_tos_offset), _ip_len(_data + _ip_len_offset), _ip_id(_data + _ip_id_offset), _ip_off(_data + _ip_off_offset), _ip_ttl(_data + _ip_ttl_offset), _ip_p(_data + _ip_p_offset), _ip_sum(_data + _ip_sum_offset), _ip_src(_data + _ip_src_offset), _ip_dst(_data + _ip_dst_offset) {} /** * Get the buffer data. * * @return the buffer data. */ uint8_t* data() { return (_data); } /** * Methods to set various IP header fields. */ void set_ip_vhl(uint8_t v) { embed_8(_ip_vhl, v); } void set_ip_tos(uint8_t v) { embed_8(_ip_tos, v); } void set_ip_len(uint16_t v) { embed_16(_ip_len, v); } void set_ip_id(uint16_t v) { embed_16(_ip_id, v); } void set_ip_off(uint16_t v) { embed_16(_ip_off, v); } void set_ip_ttl(uint8_t v) { embed_8(_ip_ttl, v); } void set_ip_p(uint8_t v) { embed_8(_ip_p, v); } void set_ip_sum(uint16_t v) { embed_16(_ip_sum, v); } void set_ip_src(const IPv4& v) { v.copy_out(_ip_src); } void set_ip_dst(const IPv4& v) { v.copy_out(_ip_dst); } /* * A method to embed the ip_len value by storing it in host order. * * @param v the ip_len value that will be stored in host order. */ void set_ip_len_host(uint16_t v) { embed_host_16(_ip_len, v); } /** * Set the IP protocol version of the header. * * @param v the IP protocol version of the header. */ void set_ip_version(uint8_t v) { uint8_t vhl = ((v << 4) | (ip_header_len() >> 2)); set_ip_vhl(vhl); } /** * Set the IPv4 packet header size (including any header options). * * @param v the IPv4 packet header size (including any header options). */ void set_ip_header_len(uint8_t v) { uint8_t vhl = ((ip_version() << 4) | (v >> 2)); set_ip_vhl(vhl); } /** * Set the IPv4 fragment offset (excluding the fragment flags). * * @param v the IPv4 fragment offset (excluding the fragment flags). */ void set_ip_fragment_offset(uint16_t v) { uint16_t off = v & IpHeader4::FRAGMENT_OFFSET_MASK; off |= ip_fragment_flags(); set_ip_off(off); } /** * Set the IPv4 fragment flags. * * @param v the IPv4 fragment flags. */ void set_ip_fragment_flags(uint16_t v) { uint16_t off = v & IpHeader4::FRAGMENT_FLAGS_MASK; off |= ip_fragment_offset(); set_ip_off(off); } private: uint8_t* _data; // The buffer data // Pointers to the fields uint8_t* _ip_vhl; // IP version and header length uint8_t* _ip_tos; // Type of service uint8_t* _ip_len; // Total length uint8_t* _ip_id; // Identification uint8_t* _ip_off; // Fragment offset field uint8_t* _ip_ttl; // Time to live uint8_t* _ip_p; // Protocol uint8_t* _ip_sum; // Checksum uint8_t* _ip_src; // Source address uint8_t* _ip_dst; // Destination address }; /** * @short IPv6 packet header. * * The IPv6 packet header has the following content: * * ip_vtc_flow (4 bytes): // 4 bits vers., 8 bits traf. class, 20 bits flow-ID * ip_plen (2 bytes): // Payload length * ip_nxt (1 byte): // Next header * ip_hlim (1 byte): // Hop limit * ip_src (16 bytes): // Source address * ip_dst (16 bytes): // Destination address */ class IpHeader6 { public: IpHeader6(const uint8_t* data) : _data(data), _ip_vtc_flow(_data + _ip_vtc_flow_offset), _ip_plen(_data + _ip_plen_offset), _ip_nxt(_data + _ip_nxt_offset), _ip_hlim(_data + _ip_hlim_offset), _ip_src(_data + _ip_src_offset), _ip_dst(_data + _ip_dst_offset) { static_assert(IpHeader6::SIZE == _ip_vtc_flow_sizeof + _ip_plen_sizeof + _ip_nxt_sizeof + _ip_hlim_sizeof + _ip_src_sizeof + _ip_dst_sizeof); static_assert(IpHeader6::SIZE == _ip_dst_offset + _ip_dst_sizeof); } static const size_t SIZE = 40; // The header size static const uint8_t IP_VERSION = 6; // IPv6 version /** * Get the IPv6 packet header size. * * Note that this is the header size only without any extention headers. * * @return the IPv6 packet header size. */ static size_t size() { return IpHeader6::SIZE; } /** * Get the buffer data. * * @return the buffer data. */ const uint8_t* data() const { return (_data); } /** * Methods to get various IP header fields. */ uint32_t ip_vtc_flow() const { return extract_32(_ip_vtc_flow); } uint16_t ip_plen() const { return extract_16(_ip_plen); } uint8_t ip_nxt() const { return extract_8(_ip_nxt); } uint8_t ip_hlim() const { return extract_8(_ip_hlim); } IPv6 ip_src() const { return IPv6(_ip_src); } IPv6 ip_dst() const { return IPv6(_ip_dst); } /** * Get the IP protocol version of the header. * * @return the IP protocol version of the header. */ uint8_t ip_version() const { uint32_t v = ip_vtc_flow() & IpHeader6::VERSION_MASK; return ((v >> IpHeader6::VERSION_SHIFT) & 0x0f); } /** * Get the IPv6 traffic class. * * @return the IPv6 traffic class. */ uint8_t ip_traffic_class() const { uint32_t tc = ip_vtc_flow() & IpHeader6::TRAFFIC_CLASS_MASK; return ((tc >> IpHeader6::TRAFFIC_CLASS_SHIFT) & 0xff); } /** * Get the IPv6 flow label. * * @return the IPv6 flow label. */ uint32_t ip_flow_label() const { uint32_t flow = ip_vtc_flow() & IpHeader6::FLOW_LABEL_MASK; return (flow >> IpHeader6::FLOW_LABEL_SHIFT); } /** * Test whether the IP header version is valid. * * @return true if the IP header version is valid, otherwise false. */ bool is_valid_version() const { return (ip_version() == IpHeader6::IP_VERSION); } protected: static const uint32_t VERSION_MASK = 0xf0000000; static const uint32_t TRAFFIC_CLASS_MASK = 0x0ff00000; static const uint32_t FLOW_LABEL_MASK = 0x000fffff; static const size_t VERSION_SHIFT = 28; static const size_t TRAFFIC_CLASS_SHIFT = 20; static const size_t FLOW_LABEL_SHIFT = 0; // Sizes of the fields static const size_t _ip_vtc_flow_sizeof = 4; static const size_t _ip_plen_sizeof = 2; static const size_t _ip_nxt_sizeof = 1; static const size_t _ip_hlim_sizeof = 1; static const size_t _ip_src_sizeof = 16; static const size_t _ip_dst_sizeof = 16; // Offsets for the fields static const size_t _ip_vtc_flow_offset = 0; static const size_t _ip_plen_offset = _ip_vtc_flow_offset + _ip_vtc_flow_sizeof; static const size_t _ip_nxt_offset = _ip_plen_offset + _ip_plen_sizeof; static const size_t _ip_hlim_offset = _ip_nxt_offset + _ip_nxt_sizeof; static const size_t _ip_src_offset = _ip_hlim_offset + _ip_hlim_sizeof; static const size_t _ip_dst_offset = _ip_src_offset + _ip_src_sizeof; private: const uint8_t* _data; // The buffer data // Pointers to the fields const uint8_t* _ip_vtc_flow; // IP version, traffic class and flow label const uint8_t* _ip_plen; // Payload length const uint8_t* _ip_nxt; // Next header const uint8_t* _ip_hlim; // Hop limit const uint8_t* _ip_src; // Source address const uint8_t* _ip_dst; // Destination address }; /** * @short Class for writing data to IPv6 packet header. */ class IpHeader6Writer : public IpHeader6 { public: IpHeader6Writer(uint8_t* data) : IpHeader6(data), _data(data), _ip_vtc_flow(_data + _ip_vtc_flow_offset), _ip_plen(_data + _ip_plen_offset), _ip_nxt(_data + _ip_nxt_offset), _ip_hlim(_data + _ip_hlim_offset), _ip_src(_data + _ip_src_offset), _ip_dst(_data + _ip_dst_offset) {} /** * Get the buffer data. * * @return the buffer data. */ uint8_t* data() { return (_data); } /** * Methods to set various IP header fields. */ void set_ip_vtc_flow(uint32_t v) { embed_32(_ip_vtc_flow, v); } void set_ip_plen(uint16_t v) { embed_16(_ip_plen, v); } void set_ip_nxt(uint8_t v) { embed_8(_ip_nxt, v); } void set_ip_hlim(uint8_t v) { embed_8(_ip_hlim, v); } void set_ip_src(const IPv6& v) { v.copy_out(_ip_src); } void set_ip_dst(const IPv6& v) { v.copy_out(_ip_dst); } /** * Set the IP protocol version of the header. * * @param v the IP protocol version of the header. */ void set_ip_version(uint8_t v) { uint32_t vtc_flow = ip_vtc_flow() & ~IpHeader6::VERSION_MASK; uint32_t shifted_v = v; shifted_v <<= IpHeader6::VERSION_SHIFT; vtc_flow |= shifted_v; set_ip_vtc_flow(vtc_flow); } /** * Set the IPv6 traffic class. * * @param v the IPv6 traffic class. */ void set_ip_traffic_class(uint8_t v) { uint32_t vtc_flow = ip_vtc_flow() & ~IpHeader6::TRAFFIC_CLASS_MASK; uint32_t shifted_v = v; shifted_v <<= IpHeader6::TRAFFIC_CLASS_SHIFT; vtc_flow |= shifted_v; set_ip_vtc_flow(vtc_flow); } /** * Set the IPv6 flow label. * * @param v the IPv6 flow label. */ void set_ip_flow_label(uint32_t v) { uint32_t vtc_flow = ip_vtc_flow() & ~IpHeader6::FLOW_LABEL_MASK; uint32_t shifted_v = v; shifted_v <<= IpHeader6::FLOW_LABEL_SHIFT; vtc_flow |= shifted_v; set_ip_vtc_flow(vtc_flow); } private: uint8_t* _data; // The buffer data // Pointers to the fields uint8_t* _ip_vtc_flow; // IP version, traffic class and flow label uint8_t* _ip_plen; // Payload length uint8_t* _ip_nxt; // Next header uint8_t* _ip_hlim; // Hop limit uint8_t* _ip_src; // Source address uint8_t* _ip_dst; // Destination address }; #endif // __LIBPROTO_PACKET_HH__