2435 lines
72 KiB
C++
2435 lines
72 KiB
C++
// -*- related-file-name: "../../lib/packet.cc" -*-
|
|
#ifndef CLICK_PACKET_HH
|
|
#define CLICK_PACKET_HH
|
|
#include <click/ipaddress.hh>
|
|
#include <click/glue.hh>
|
|
#include <click/timestamp.hh>
|
|
#if CLICK_LINUXMODULE
|
|
# include <click/skbmgr.hh>
|
|
#else
|
|
# include <click/atomic.hh>
|
|
#endif
|
|
#if CLICK_BSDMODULE
|
|
# include <sys/stddef.h>
|
|
#endif
|
|
#if CLICK_NS
|
|
# include <click/simclick.h>
|
|
#endif
|
|
#if (CLICK_USERLEVEL || CLICK_NS || CLICK_MINIOS) && (!HAVE_MULTITHREAD || HAVE___THREAD_STORAGE_CLASS)
|
|
# define HAVE_CLICK_PACKET_POOL 1
|
|
#endif
|
|
#ifndef CLICK_PACKET_DEPRECATED_ENUM
|
|
# define CLICK_PACKET_DEPRECATED_ENUM CLICK_DEPRECATED_ENUM
|
|
#endif
|
|
struct click_ether;
|
|
struct click_ip;
|
|
struct click_icmp;
|
|
struct click_ip6;
|
|
struct click_tcp;
|
|
struct click_udp;
|
|
CLICK_DECLS
|
|
|
|
class IP6Address;
|
|
class WritablePacket;
|
|
|
|
class Packet { public:
|
|
|
|
/** @name Data */
|
|
//@{
|
|
// PACKET CREATION
|
|
|
|
enum {
|
|
#ifdef CLICK_MINIOS
|
|
default_headroom = 48, ///< Increase headroom for improved performance.
|
|
#else
|
|
default_headroom = 28, ///< Default packet headroom() for
|
|
/// Packet::make(). 4-byte aligned.
|
|
#endif
|
|
min_buffer_length = 64 ///< Minimum buffer_length() for
|
|
/// Packet::make()
|
|
};
|
|
|
|
static WritablePacket *make(uint32_t headroom, const void *data,
|
|
uint32_t length, uint32_t tailroom) CLICK_WARN_UNUSED_RESULT;
|
|
static inline WritablePacket *make(const void *data, uint32_t length) CLICK_WARN_UNUSED_RESULT;
|
|
static inline WritablePacket *make(uint32_t length) CLICK_WARN_UNUSED_RESULT;
|
|
#if CLICK_LINUXMODULE
|
|
static Packet *make(struct sk_buff *skb) CLICK_WARN_UNUSED_RESULT;
|
|
#endif
|
|
#if CLICK_BSDMODULE
|
|
// Packet::make(mbuf *) wraps a Packet around an existing mbuf.
|
|
// Packet now owns the mbuf.
|
|
static inline Packet *make(struct mbuf *mbuf) CLICK_WARN_UNUSED_RESULT;
|
|
#endif
|
|
#if CLICK_USERLEVEL || CLICK_MINIOS
|
|
typedef void (*buffer_destructor_type)(unsigned char* buf, size_t sz, void* argument);
|
|
static WritablePacket* make(unsigned char* data, uint32_t length,
|
|
buffer_destructor_type buffer_destructor,
|
|
void* argument = (void*) 0, int headroom = 0, int tailroom = 0) CLICK_WARN_UNUSED_RESULT;
|
|
#endif
|
|
|
|
static void static_cleanup();
|
|
|
|
inline void kill();
|
|
|
|
inline bool shared() const;
|
|
Packet *clone() CLICK_WARN_UNUSED_RESULT;
|
|
inline WritablePacket *uniqueify() CLICK_WARN_UNUSED_RESULT;
|
|
|
|
inline const unsigned char *data() const;
|
|
inline const unsigned char *end_data() const;
|
|
inline uint32_t length() const;
|
|
inline uint32_t headroom() const;
|
|
inline uint32_t tailroom() const;
|
|
inline const unsigned char *buffer() const;
|
|
inline const unsigned char *end_buffer() const;
|
|
inline uint32_t buffer_length() const;
|
|
|
|
#if CLICK_LINUXMODULE
|
|
struct sk_buff *skb() { return (struct sk_buff *)this; }
|
|
const struct sk_buff *skb() const { return (const struct sk_buff*)this; }
|
|
#elif CLICK_BSDMODULE
|
|
struct mbuf *m() { return _m; }
|
|
const struct mbuf *m() const { return (const struct mbuf *)_m; }
|
|
struct mbuf *steal_m();
|
|
struct mbuf *dup_jumbo_m(struct mbuf *mbuf);
|
|
#elif CLICK_USERLEVEL || CLICK_MINIOS
|
|
buffer_destructor_type buffer_destructor() const {
|
|
return _destructor;
|
|
}
|
|
|
|
void set_buffer_destructor(buffer_destructor_type destructor) {
|
|
_destructor = destructor;
|
|
}
|
|
|
|
void* destructor_argument() {
|
|
return _destructor_argument;
|
|
}
|
|
|
|
void reset_buffer() {
|
|
assert(!shared());
|
|
_head = _data = _tail = _end = 0;
|
|
_destructor = 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
/** @brief Add space for a header before the packet.
|
|
* @param len amount of space to add
|
|
* @return packet with added header space, or null on failure
|
|
*
|
|
* Returns a packet with an additional @a len bytes of uninitialized space
|
|
* before the current packet's data(). A copy of the packet data is made
|
|
* if there isn't enough headroom() in the current packet, or if the
|
|
* current packet is shared(). If no copy is made, this operation is
|
|
* quite efficient.
|
|
*
|
|
* If a data copy would be required, but the copy fails because of lack of
|
|
* memory, then the current packet is freed.
|
|
*
|
|
* push() is usually used like this:
|
|
* @code
|
|
* WritablePacket *q = p->push(14);
|
|
* if (!q)
|
|
* return 0;
|
|
* // p must not be used here.
|
|
* @endcode
|
|
*
|
|
* @post new length() == old length() + @a len (if no failure)
|
|
*
|
|
* @sa nonunique_push, push_mac_header, pull */
|
|
WritablePacket *push(uint32_t len) CLICK_WARN_UNUSED_RESULT;
|
|
|
|
/** @brief Add space for a MAC header before the packet.
|
|
* @param len amount of space to add and length of MAC header
|
|
* @return packet with added header space, or null on failure
|
|
*
|
|
* Combines the action of push() and set_mac_header(). @a len bytes are
|
|
* pushed for a MAC header, and on success, the packet's returned MAC and
|
|
* network header pointers are set as by set_mac_header(data(), @a len).
|
|
*
|
|
* @sa push */
|
|
WritablePacket *push_mac_header(uint32_t len) CLICK_WARN_UNUSED_RESULT;
|
|
|
|
/** @brief Add space for a header before the packet.
|
|
* @param len amount of space to add
|
|
* @return packet with added header space, or null on failure
|
|
*
|
|
* This is a variant of push(). Returns a packet with an additional @a
|
|
* len bytes of uninitialized space before the current packet's data(). A
|
|
* copy of the packet data is made if there isn't enough headroom() in the
|
|
* current packet. However, no copy is made if the current packet is
|
|
* shared; and if no copy is made, this operation is quite efficient.
|
|
*
|
|
* If a data copy would be required, but the copy fails because of lack of
|
|
* memory, then the current packet is freed.
|
|
*
|
|
* @note Unlike push(), nonunique_push() returns a Packet object, which
|
|
* has non-writable data.
|
|
*
|
|
* @sa push */
|
|
Packet *nonunique_push(uint32_t len) CLICK_WARN_UNUSED_RESULT;
|
|
|
|
/** @brief Remove a header from the front of the packet.
|
|
* @param len amount of space to remove
|
|
*
|
|
* Removes @a len bytes from the initial part of the packet, usually
|
|
* corresponding to some network header (for example, pull(14) removes an
|
|
* Ethernet header). This operation is efficient: it just bumps a
|
|
* pointer.
|
|
*
|
|
* It is an error to attempt to pull more than length() bytes.
|
|
*
|
|
* @post new data() == old data() + @a len
|
|
* @post new length() == old length() - @a len
|
|
*
|
|
* @sa push */
|
|
void pull(uint32_t len);
|
|
|
|
/** @brief Add space for data after the packet.
|
|
* @param len amount of space to add
|
|
* @return packet with added trailer space, or null on failure
|
|
*
|
|
* Returns a packet with an additional @a len bytes of uninitialized space
|
|
* after the current packet's data (starting at end_data()). A copy of
|
|
* the packet data is made if there isn't enough tailroom() in the current
|
|
* packet, or if the current packet is shared(). If no copy is made, this
|
|
* operation is quite efficient.
|
|
*
|
|
* If a data copy would be required, but the copy fails because of lack of
|
|
* memory, then the current packet is freed.
|
|
*
|
|
* put() is usually used like this:
|
|
* @code
|
|
* WritablePacket *q = p->put(100);
|
|
* if (!q)
|
|
* return 0;
|
|
* // p must not be used here.
|
|
* @endcode
|
|
*
|
|
* @post new length() == old length() + @a len (if no failure)
|
|
*
|
|
* @sa nonunique_put, take */
|
|
WritablePacket *put(uint32_t len) CLICK_WARN_UNUSED_RESULT;
|
|
|
|
/** @brief Add space for data after the packet.
|
|
* @param len amount of space to add
|
|
* @return packet with added trailer space, or null on failure
|
|
*
|
|
* This is a variant of put(). Returns a packet with an additional @a len
|
|
* bytes of uninitialized space after the current packet's data (starting
|
|
* at end_data()). A copy of the packet data is made if there isn't
|
|
* enough tailroom() in the current packet. However, no copy is made if
|
|
* the current packet is shared; and if no copy is made, this operation is
|
|
* quite efficient.
|
|
*
|
|
* If a data copy would be required, but the copy fails because of lack of
|
|
* memory, then the current packet is freed.
|
|
*
|
|
* @sa put */
|
|
Packet *nonunique_put(uint32_t len) CLICK_WARN_UNUSED_RESULT;
|
|
|
|
/** @brief Remove space from the end of the packet.
|
|
* @param len amount of space to remove
|
|
*
|
|
* Removes @a len bytes from the end of the packet. This operation is
|
|
* efficient: it just bumps a pointer.
|
|
*
|
|
* It is an error to attempt to pull more than length() bytes.
|
|
*
|
|
* @post new data() == old data()
|
|
* @post new end_data() == old end_data() - @a len
|
|
* @post new length() == old length() - @a len
|
|
*
|
|
* @sa push */
|
|
void take(uint32_t len);
|
|
|
|
|
|
/** @brief Shift packet data within the data buffer.
|
|
* @param offset amount to shift packet data
|
|
* @param free_on_failure if true, then delete the input packet on failure
|
|
* @return a packet with shifted data, or null on failure
|
|
*
|
|
* Useful to align packet data. For example, if the packet's embedded IP
|
|
* header is located at pointer value 0x8CCA03, then shift_data(1) or
|
|
* shift_data(-3) will both align the header on a 4-byte boundary.
|
|
*
|
|
* If the packet is shared() or there isn't enough headroom or tailroom
|
|
* for the operation, the packet is passed to uniqueify() first. This can
|
|
* fail if there isn't enough memory. If it fails, shift_data returns
|
|
* null, and if @a free_on_failure is true (the default), the input packet
|
|
* is freed.
|
|
*
|
|
* The packet's mac_header, network_header, and transport_header areas are
|
|
* preserved, even if they lie within the headroom. Any headroom outside
|
|
* these regions may be overwritten, as may any tailroom.
|
|
*
|
|
* @post new data() == old data() + @a offset (if no copy is made)
|
|
* @post new buffer() == old buffer() (if no copy is made) */
|
|
Packet *shift_data(int offset, bool free_on_failure = true) CLICK_WARN_UNUSED_RESULT;
|
|
#if CLICK_USERLEVEL || CLICK_MINIOS
|
|
inline void shrink_data(const unsigned char *data, uint32_t length);
|
|
inline void change_headroom_and_length(uint32_t headroom, uint32_t length);
|
|
#endif
|
|
bool copy(Packet* p, int headroom=0);
|
|
//@}
|
|
|
|
/** @name Header Pointers */
|
|
//@{
|
|
inline bool has_mac_header() const;
|
|
inline const unsigned char *mac_header() const;
|
|
inline int mac_header_offset() const;
|
|
inline uint32_t mac_header_length() const;
|
|
inline int mac_length() const;
|
|
inline void set_mac_header(const unsigned char *p);
|
|
inline void set_mac_header(const unsigned char *p, uint32_t len);
|
|
inline void clear_mac_header();
|
|
|
|
inline bool has_network_header() const;
|
|
inline const unsigned char *network_header() const;
|
|
inline int network_header_offset() const;
|
|
inline uint32_t network_header_length() const;
|
|
inline int network_length() const;
|
|
inline void set_network_header(const unsigned char *p, uint32_t len);
|
|
inline void set_network_header_length(uint32_t len);
|
|
inline void clear_network_header();
|
|
|
|
inline bool has_transport_header() const;
|
|
inline const unsigned char *transport_header() const;
|
|
inline int transport_header_offset() const;
|
|
inline int transport_length() const;
|
|
inline void clear_transport_header();
|
|
|
|
// CONVENIENCE HEADER ANNOTATIONS
|
|
inline const click_ether *ether_header() const;
|
|
inline void set_ether_header(const click_ether *ethh);
|
|
|
|
inline const click_ip *ip_header() const;
|
|
inline int ip_header_offset() const;
|
|
inline uint32_t ip_header_length() const;
|
|
inline void set_ip_header(const click_ip *iph, uint32_t len);
|
|
|
|
inline const click_ip6 *ip6_header() const;
|
|
inline int ip6_header_offset() const;
|
|
inline uint32_t ip6_header_length() const;
|
|
inline void set_ip6_header(const click_ip6 *ip6h);
|
|
inline void set_ip6_header(const click_ip6 *ip6h, uint32_t len);
|
|
|
|
inline const click_icmp *icmp_header() const;
|
|
inline const click_tcp *tcp_header() const;
|
|
inline const click_udp *udp_header() const;
|
|
//@}
|
|
|
|
#if CLICK_LINUXMODULE
|
|
# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && NET_SKBUFF_DATA_USES_OFFSET) || \
|
|
(LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
|
|
protected:
|
|
typedef typeof(((struct sk_buff*)0)->mac_header) mac_header_type;
|
|
typedef typeof(((struct sk_buff*)0)->network_header) network_header_type;
|
|
typedef typeof(((struct sk_buff*)0)->transport_header) transport_header_type;
|
|
# endif
|
|
#endif
|
|
|
|
private:
|
|
/** @cond never */
|
|
union Anno;
|
|
#if CLICK_LINUXMODULE
|
|
const Anno *xanno() const { return (const Anno *)skb()->cb; }
|
|
Anno *xanno() { return (Anno *)skb()->cb; }
|
|
#else
|
|
const Anno *xanno() const { return &_aa.cb; }
|
|
Anno *xanno() { return &_aa.cb; }
|
|
#endif
|
|
/** @endcond never */
|
|
public:
|
|
|
|
/** @name Annotations */
|
|
//@{
|
|
|
|
enum {
|
|
anno_size = 48 ///< Size of annotation area.
|
|
};
|
|
|
|
/** @brief Return the timestamp annotation. */
|
|
inline const Timestamp ×tamp_anno() const;
|
|
/** @overload */
|
|
inline Timestamp ×tamp_anno();
|
|
/** @brief Set the timestamp annotation.
|
|
* @param t new timestamp */
|
|
inline void set_timestamp_anno(const Timestamp &t);
|
|
|
|
/** @brief Return the device annotation. */
|
|
inline net_device *device_anno() const;
|
|
/** @brief Set the device annotation */
|
|
inline void set_device_anno(net_device *dev);
|
|
|
|
/** @brief Values for packet_type_anno().
|
|
* Must agree with Linux's PACKET_ constants in <linux/if_packet.h>. */
|
|
enum PacketType {
|
|
HOST = 0, /**< Packet was sent to this host. */
|
|
BROADCAST = 1, /**< Packet was sent to a link-level multicast
|
|
address. */
|
|
MULTICAST = 2, /**< Packet was sent to a link-level multicast
|
|
address. */
|
|
OTHERHOST = 3, /**< Packet was sent to a different host, but
|
|
received anyway. The receiving device is
|
|
probably in promiscuous mode. */
|
|
OUTGOING = 4, /**< Packet was generated by this host and is
|
|
being sent elsewhere. */
|
|
LOOPBACK = 5,
|
|
FASTROUTE = 6
|
|
};
|
|
/** @brief Return the packet type annotation. */
|
|
inline PacketType packet_type_anno() const;
|
|
/** @brief Set the packet type annotation. */
|
|
inline void set_packet_type_anno(PacketType t);
|
|
|
|
#if CLICK_NS
|
|
class SimPacketinfoWrapper { public:
|
|
simclick_simpacketinfo _pinfo;
|
|
SimPacketinfoWrapper() {
|
|
// The uninitialized value for the simulator packet data can't be
|
|
// all zeros (0 is a valid packet id) or random junk out of memory
|
|
// since the simulator will look at this info to see if the packet
|
|
// was originally generated by it. Accidental collisions with
|
|
// other packet IDs or bogus packet IDs can cause weird things to
|
|
// happen. So we set it to all -1 here to keep the simulator from
|
|
// getting confused.
|
|
memset(&_pinfo,-1,sizeof(_pinfo));
|
|
}
|
|
};
|
|
simclick_simpacketinfo *get_sim_packetinfo() {
|
|
return &(_sim_packetinfo._pinfo);
|
|
}
|
|
void set_sim_packetinfo(simclick_simpacketinfo* pinfo) {
|
|
_sim_packetinfo._pinfo = *pinfo;
|
|
}
|
|
#endif
|
|
|
|
/** @brief Return the next packet annotation. */
|
|
inline Packet *next() const;
|
|
/** @overload */
|
|
inline Packet *&next();
|
|
/** @brief Set the next packet annotation. */
|
|
inline void set_next(Packet *p);
|
|
|
|
/** @brief Return the previous packet annotation. */
|
|
inline Packet *prev() const;
|
|
/** @overload */
|
|
inline Packet *&prev();
|
|
/** @brief Set the previous packet annotation. */
|
|
inline void set_prev(Packet *p);
|
|
|
|
enum {
|
|
dst_ip_anno_offset = 0, dst_ip_anno_size = 4,
|
|
dst_ip6_anno_offset = 0, dst_ip6_anno_size = 16
|
|
};
|
|
|
|
/** @brief Return the destination IPv4 address annotation.
|
|
*
|
|
* The value is taken from the address annotation area. */
|
|
inline IPAddress dst_ip_anno() const;
|
|
|
|
/** @brief Set the destination IPv4 address annotation.
|
|
*
|
|
* The value is stored in the address annotation area. */
|
|
inline void set_dst_ip_anno(IPAddress addr);
|
|
|
|
/** @brief Return a pointer to the annotation area.
|
|
*
|
|
* The area is @link Packet::anno_size anno_size @endlink bytes long. */
|
|
void *anno() { return xanno(); }
|
|
|
|
/** @overload */
|
|
const void *anno() const { return xanno(); }
|
|
|
|
/** @brief Return a pointer to the annotation area as uint8_ts. */
|
|
uint8_t *anno_u8() { return &xanno()->u8[0]; }
|
|
|
|
/** @brief overload */
|
|
const uint8_t *anno_u8() const { return &xanno()->u8[0]; }
|
|
|
|
/** @brief Return a pointer to the annotation area as uint32_ts. */
|
|
uint32_t *anno_u32() { return &xanno()->u32[0]; }
|
|
|
|
/** @brief overload */
|
|
const uint32_t *anno_u32() const { return &xanno()->u32[0]; }
|
|
|
|
/** @brief Return annotation byte at offset @a i.
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink */
|
|
uint8_t anno_u8(int i) const {
|
|
assert(i >= 0 && i < anno_size);
|
|
return xanno()->u8[i];
|
|
}
|
|
|
|
/** @brief Set annotation byte at offset @a i.
|
|
* @param i annotation offset in bytes
|
|
* @param x value
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink */
|
|
void set_anno_u8(int i, uint8_t x) {
|
|
assert(i >= 0 && i < anno_size);
|
|
xanno()->u8[i] = x;
|
|
}
|
|
|
|
/** @brief Return 16-bit annotation at offset @a i.
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 1
|
|
* @pre On aligned targets, @a i must be evenly divisible by 2.
|
|
*
|
|
* Affects annotation bytes [@a i, @a i+1]. */
|
|
uint16_t anno_u16(int i) const {
|
|
assert(i >= 0 && i < anno_size - 1);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % 2 == 0);
|
|
#endif
|
|
return *reinterpret_cast<const click_aliasable_uint16_t *>(xanno()->c + i);
|
|
}
|
|
|
|
/** @brief Set 16-bit annotation at offset @a i.
|
|
* @param i annotation offset in bytes
|
|
* @param x value
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 1
|
|
* @pre On aligned targets, @a i must be evenly divisible by 2.
|
|
*
|
|
* Affects annotation bytes [@a i, @a i+1]. */
|
|
void set_anno_u16(int i, uint16_t x) {
|
|
assert(i >= 0 && i < anno_size - 1);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % 2 == 0);
|
|
#endif
|
|
*reinterpret_cast<click_aliasable_uint16_t *>(xanno()->c + i) = x;
|
|
}
|
|
|
|
/** @brief Return 16-bit annotation at offset @a i.
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 1
|
|
* @pre On aligned targets, @a i must be evenly divisible by 2.
|
|
*
|
|
* Affects annotation bytes [@a i, @a i+1]. */
|
|
int16_t anno_s16(int i) const {
|
|
assert(i >= 0 && i < anno_size - 1);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % 2 == 0);
|
|
#endif
|
|
return *reinterpret_cast<const click_aliasable_int16_t *>(xanno()->c + i);
|
|
}
|
|
|
|
/** @brief Set 16-bit annotation at offset @a i.
|
|
* @param i annotation offset in bytes
|
|
* @param x value
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 1
|
|
* @pre On aligned targets, @a i must be evenly divisible by 2.
|
|
*
|
|
* Affects annotation bytes [@a i, @a i+1]. */
|
|
void set_anno_s16(int i, int16_t x) {
|
|
assert(i >= 0 && i < anno_size - 1);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % 2 == 0);
|
|
#endif
|
|
*reinterpret_cast<click_aliasable_int16_t *>(xanno()->c + i) = x;
|
|
}
|
|
|
|
/** @brief Return 32-bit annotation at offset @a i.
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 3
|
|
* @pre On aligned targets, @a i must be evenly divisible by 4.
|
|
*
|
|
* Affects user annotation bytes [@a i, @a i+3]. */
|
|
uint32_t anno_u32(int i) const {
|
|
assert(i >= 0 && i < anno_size - 3);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % 4 == 0);
|
|
#endif
|
|
return *reinterpret_cast<const click_aliasable_uint32_t *>(xanno()->c + i);
|
|
}
|
|
|
|
/** @brief Set 32-bit annotation at offset @a i.
|
|
* @param i annotation offset in bytes
|
|
* @param x value
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 3
|
|
* @pre On aligned targets, @a i must be evenly divisible by 4.
|
|
*
|
|
* Affects user annotation bytes [@a i, @a i+3]. */
|
|
void set_anno_u32(int i, uint32_t x) {
|
|
assert(i >= 0 && i < anno_size - 3);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % 4 == 0);
|
|
#endif
|
|
*reinterpret_cast<click_aliasable_uint32_t *>(xanno()->c + i) = x;
|
|
}
|
|
|
|
/** @brief Return 32-bit annotation at offset @a i.
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 3
|
|
*
|
|
* Affects user annotation bytes [4*@a i, 4*@a i+3]. */
|
|
int32_t anno_s32(int i) const {
|
|
assert(i >= 0 && i < anno_size - 3);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % 4 == 0);
|
|
#endif
|
|
return *reinterpret_cast<const click_aliasable_int32_t *>(xanno()->c + i);
|
|
}
|
|
|
|
/** @brief Set 32-bit annotation at offset @a i.
|
|
* @param i annotation offset in bytes
|
|
* @param x value
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 3
|
|
* @pre On aligned targets, @a i must be evenly divisible by 4.
|
|
*
|
|
* Affects user annotation bytes [@a i, @a i+3]. */
|
|
void set_anno_s32(int i, int32_t x) {
|
|
assert(i >= 0 && i < anno_size - 3);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % 4 == 0);
|
|
#endif
|
|
*reinterpret_cast<click_aliasable_int32_t *>(xanno()->c + i) = x;
|
|
}
|
|
|
|
#if HAVE_INT64_TYPES
|
|
/** @brief Return 64-bit annotation at offset @a i.
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 7
|
|
* @pre On aligned targets, @a i must be aligned properly for uint64_t.
|
|
*
|
|
* Affects user annotation bytes [@a i, @a i+7]. */
|
|
uint64_t anno_u64(int i) const {
|
|
assert(i >= 0 && i < anno_size - 7);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % __alignof__(uint64_t) == 0);
|
|
#endif
|
|
return *reinterpret_cast<const click_aliasable_uint64_t *>(xanno()->c + i);
|
|
}
|
|
|
|
/** @brief Set 64-bit annotation at offset @a i.
|
|
* @param i annotation offset in bytes
|
|
* @param x value
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - 7
|
|
* @pre On aligned targets, @a i must be aligned properly for uint64_t.
|
|
*
|
|
* Affects user annotation bytes [@a i, @a i+7]. */
|
|
void set_anno_u64(int i, uint64_t x) {
|
|
assert(i >= 0 && i < anno_size - 7);
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % __alignof__(uint64_t) == 0);
|
|
#endif
|
|
*reinterpret_cast<click_aliasable_uint64_t *>(xanno()->c + i) = x;
|
|
}
|
|
#endif
|
|
|
|
/** @brief Return void * sized annotation at offset @a i.
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - sizeof(void *)
|
|
* @pre On aligned targets, @a i must be aligned properly.
|
|
*
|
|
* Affects user annotation bytes [@a i, @a i+sizeof(void *)]. */
|
|
void *anno_ptr(int i) const {
|
|
assert(i >= 0 && i <= anno_size - (int)sizeof(void *));
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % __alignof__(void *) == 0);
|
|
#endif
|
|
return *reinterpret_cast<const click_aliasable_void_pointer_t *>(xanno()->c + i);
|
|
}
|
|
|
|
/** @brief Set void * sized annotation at offset @a i.
|
|
* @param i annotation offset in bytes
|
|
* @param x value
|
|
* @pre 0 <= @a i < @link Packet::anno_size anno_size @endlink - sizeof(void *)
|
|
* @pre On aligned targets, @a i must be aligned properly.
|
|
*
|
|
* Affects user annotation bytes [@a i, @a i+sizeof(void *)]. */
|
|
void set_anno_ptr(int i, const void *x) {
|
|
assert(i >= 0 && i <= anno_size - (int)sizeof(void *));
|
|
#if !HAVE_INDIFFERENT_ALIGNMENT
|
|
assert(i % __alignof__(void *) == 0);
|
|
#endif
|
|
*reinterpret_cast<click_aliasable_void_pointer_t *>(xanno()->c + i) = const_cast<void *>(x);
|
|
}
|
|
|
|
#if !CLICK_LINUXMODULE
|
|
inline Packet* data_packet() {
|
|
return _data_packet;
|
|
}
|
|
#endif
|
|
|
|
inline void clear_annotations(bool all = true);
|
|
inline void copy_annotations(const Packet *);
|
|
//@}
|
|
|
|
/** @cond never */
|
|
enum {
|
|
DEFAULT_HEADROOM = default_headroom,
|
|
MIN_BUFFER_LENGTH = min_buffer_length,
|
|
addr_anno_offset = 0,
|
|
addr_anno_size = 16,
|
|
user_anno_offset = 16,
|
|
user_anno_size = 32,
|
|
ADDR_ANNO_SIZE = addr_anno_size,
|
|
USER_ANNO_SIZE = user_anno_size,
|
|
USER_ANNO_U16_SIZE = USER_ANNO_SIZE / 2,
|
|
USER_ANNO_U32_SIZE = USER_ANNO_SIZE / 4,
|
|
USER_ANNO_U64_SIZE = USER_ANNO_SIZE / 8
|
|
} CLICK_PACKET_DEPRECATED_ENUM;
|
|
inline const unsigned char *buffer_data() const CLICK_DEPRECATED;
|
|
inline void *addr_anno() CLICK_DEPRECATED;
|
|
inline const void *addr_anno() const CLICK_DEPRECATED;
|
|
inline void *user_anno() CLICK_DEPRECATED;
|
|
inline const void *user_anno() const CLICK_DEPRECATED;
|
|
inline uint8_t *user_anno_u8() CLICK_DEPRECATED;
|
|
inline const uint8_t *user_anno_u8() const CLICK_DEPRECATED;
|
|
inline uint32_t *user_anno_u32() CLICK_DEPRECATED;
|
|
inline const uint32_t *user_anno_u32() const CLICK_DEPRECATED;
|
|
inline uint8_t user_anno_u8(int i) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_u8(int i, uint8_t v) CLICK_DEPRECATED;
|
|
inline uint16_t user_anno_u16(int i) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_u16(int i, uint16_t v) CLICK_DEPRECATED;
|
|
inline uint32_t user_anno_u32(int i) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_u32(int i, uint32_t v) CLICK_DEPRECATED;
|
|
inline int32_t user_anno_s32(int i) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_s32(int i, int32_t v) CLICK_DEPRECATED;
|
|
#if HAVE_INT64_TYPES
|
|
inline uint64_t user_anno_u64(int i) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_u64(int i, uint64_t v) CLICK_DEPRECATED;
|
|
#endif
|
|
inline const uint8_t *all_user_anno() const CLICK_DEPRECATED;
|
|
inline uint8_t *all_user_anno() CLICK_DEPRECATED;
|
|
inline const uint32_t *all_user_anno_u() const CLICK_DEPRECATED;
|
|
inline uint32_t *all_user_anno_u() CLICK_DEPRECATED;
|
|
inline uint8_t user_anno_c(int) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_c(int, uint8_t) CLICK_DEPRECATED;
|
|
inline int16_t user_anno_s(int) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_s(int, int16_t) CLICK_DEPRECATED;
|
|
inline uint16_t user_anno_us(int) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_us(int, uint16_t) CLICK_DEPRECATED;
|
|
inline int32_t user_anno_i(int) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_i(int, int32_t) CLICK_DEPRECATED;
|
|
inline uint32_t user_anno_u(int) const CLICK_DEPRECATED;
|
|
inline void set_user_anno_u(int, uint32_t) CLICK_DEPRECATED;
|
|
/** @endcond never */
|
|
|
|
private:
|
|
|
|
// Anno must fit in sk_buff's char cb[48].
|
|
/** @cond never */
|
|
union Anno {
|
|
char c[anno_size];
|
|
uint8_t u8[anno_size];
|
|
uint16_t u16[anno_size / 2];
|
|
uint32_t u32[anno_size / 4];
|
|
#if HAVE_INT64_TYPES
|
|
uint64_t u64[anno_size / 8];
|
|
#endif
|
|
// allocations: see packet_anno.hh
|
|
};
|
|
|
|
#if !CLICK_LINUXMODULE
|
|
// All packet annotations are stored in AllAnno so that
|
|
// clear_annotations(true) can memset() the structure to zero.
|
|
struct AllAnno {
|
|
Anno cb;
|
|
unsigned char *mac;
|
|
unsigned char *nh;
|
|
unsigned char *h;
|
|
PacketType pkt_type;
|
|
char timestamp[sizeof(Timestamp)];
|
|
Packet *next;
|
|
Packet *prev;
|
|
};
|
|
#endif
|
|
/** @endcond never */
|
|
|
|
#if !CLICK_LINUXMODULE
|
|
// User-space and BSD kernel module implementations.
|
|
atomic_uint32_t _use_count;
|
|
Packet *_data_packet;
|
|
/* mimic Linux sk_buff */
|
|
unsigned char *_head; /* start of allocated buffer */
|
|
unsigned char *_data; /* where the packet starts */
|
|
unsigned char *_tail; /* one beyond end of packet */
|
|
unsigned char *_end; /* one beyond end of allocated buffer */
|
|
# if CLICK_BSDMODULE
|
|
struct mbuf *_m;
|
|
# endif
|
|
AllAnno _aa;
|
|
# if CLICK_NS
|
|
SimPacketinfoWrapper _sim_packetinfo;
|
|
# endif
|
|
# if CLICK_USERLEVEL || CLICK_MINIOS
|
|
buffer_destructor_type _destructor;
|
|
void* _destructor_argument;
|
|
# endif
|
|
#endif
|
|
|
|
inline Packet() {
|
|
#if CLICK_LINUXMODULE
|
|
panic("Packet constructor");
|
|
#endif
|
|
}
|
|
Packet(const Packet &x);
|
|
~Packet();
|
|
Packet &operator=(const Packet &x);
|
|
|
|
#if !CLICK_LINUXMODULE
|
|
bool alloc_data(uint32_t headroom, uint32_t length, uint32_t tailroom);
|
|
#endif
|
|
#if CLICK_BSDMODULE
|
|
static void assimilate_mbuf(Packet *p);
|
|
void assimilate_mbuf();
|
|
#endif
|
|
|
|
inline void shift_header_annotations(const unsigned char *old_head, int32_t extra_headroom);
|
|
WritablePacket *expensive_uniqueify(int32_t extra_headroom, int32_t extra_tailroom, bool free_on_failure);
|
|
WritablePacket *expensive_push(uint32_t nbytes);
|
|
WritablePacket *expensive_put(uint32_t nbytes);
|
|
|
|
friend class WritablePacket;
|
|
|
|
};
|
|
|
|
|
|
class WritablePacket : public Packet { public:
|
|
|
|
inline unsigned char *data() const;
|
|
inline unsigned char *end_data() const;
|
|
inline unsigned char *buffer() const;
|
|
inline unsigned char *end_buffer() const;
|
|
inline unsigned char *mac_header() const;
|
|
inline click_ether *ether_header() const;
|
|
inline unsigned char *network_header() const;
|
|
inline click_ip *ip_header() const;
|
|
inline click_ip6 *ip6_header() const;
|
|
inline unsigned char *transport_header() const;
|
|
inline click_icmp *icmp_header() const;
|
|
inline click_tcp *tcp_header() const;
|
|
inline click_udp *udp_header() const;
|
|
|
|
/** @cond never */
|
|
inline unsigned char *buffer_data() const CLICK_DEPRECATED;
|
|
/** @endcond never */
|
|
|
|
private:
|
|
|
|
inline WritablePacket() { }
|
|
#if !CLICK_LINUXMODULE
|
|
inline void initialize();
|
|
#endif
|
|
WritablePacket(const Packet &x);
|
|
~WritablePacket() { }
|
|
|
|
#if HAVE_CLICK_PACKET_POOL
|
|
static WritablePacket *pool_allocate(bool with_data);
|
|
static WritablePacket *pool_allocate(uint32_t headroom, uint32_t length,
|
|
uint32_t tailroom);
|
|
static void recycle(WritablePacket *p);
|
|
#endif
|
|
|
|
friend class Packet;
|
|
|
|
};
|
|
|
|
|
|
/** @brief Clear all packet annotations.
|
|
* @param all If true, clear all annotations. If false, clear only Click's
|
|
* internal annotations.
|
|
*
|
|
* All user annotations and the address annotation are set to zero, the packet
|
|
* type annotation is set to HOST, the device annotation and all header
|
|
* pointers are set to null, the timestamp annotation is cleared, and the
|
|
* next/prev-packet annotations are set to null.
|
|
*
|
|
* If @a all is false, then the packet type, device, timestamp, header, and
|
|
* next/prev-packet annotations are left alone.
|
|
*/
|
|
inline void
|
|
Packet::clear_annotations(bool all)
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
memset(xanno(), 0, sizeof(Anno));
|
|
if (all) {
|
|
set_packet_type_anno(HOST);
|
|
set_device_anno(0);
|
|
set_timestamp_anno(Timestamp());
|
|
|
|
clear_mac_header();
|
|
clear_network_header();
|
|
clear_transport_header();
|
|
|
|
set_next(0);
|
|
set_prev(0);
|
|
}
|
|
#else
|
|
memset(&_aa, 0, all ? sizeof(AllAnno) : sizeof(Anno));
|
|
#endif
|
|
}
|
|
|
|
/** @brief Copy most packet annotations from @a p.
|
|
* @param p source of annotations
|
|
*
|
|
* This packet's user annotations, address annotation, packet type annotation,
|
|
* device annotation, and timestamp annotation are set to the corresponding
|
|
* annotations from @a p.
|
|
*
|
|
* @note The next/prev-packet and header annotations are not copied. */
|
|
inline void
|
|
Packet::copy_annotations(const Packet *p)
|
|
{
|
|
*xanno() = *p->xanno();
|
|
set_packet_type_anno(p->packet_type_anno());
|
|
set_device_anno(p->device_anno());
|
|
set_timestamp_anno(p->timestamp_anno());
|
|
}
|
|
|
|
|
|
#if !CLICK_LINUXMODULE
|
|
inline void
|
|
WritablePacket::initialize()
|
|
{
|
|
_use_count = 1;
|
|
_data_packet = 0;
|
|
# if CLICK_USERLEVEL || CLICK_MINIOS
|
|
_destructor = 0;
|
|
# elif CLICK_BSDMODULE
|
|
_m = 0;
|
|
# endif
|
|
clear_annotations();
|
|
}
|
|
#endif
|
|
|
|
/** @brief Return the packet's data pointer.
|
|
*
|
|
* This is the pointer to the first byte of packet data. */
|
|
inline const unsigned char *
|
|
Packet::data() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return skb()->data;
|
|
#else
|
|
return _data;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the packet's end data pointer.
|
|
*
|
|
* The result points at the byte following the packet data.
|
|
* @invariant end_data() == data() + length() */
|
|
inline const unsigned char *
|
|
Packet::end_data() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
return skb_tail_pointer(skb());
|
|
# else
|
|
return skb()->tail;
|
|
# endif
|
|
#else
|
|
return _tail;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return a pointer to the packet's data buffer.
|
|
*
|
|
* The result points at the packet's headroom, not its data.
|
|
* @invariant buffer() == data() - headroom() */
|
|
inline const unsigned char *
|
|
Packet::buffer() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return skb()->head;
|
|
#else
|
|
return _head;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the packet's end data buffer pointer.
|
|
*
|
|
* The result points past the packet's tailroom.
|
|
* @invariant end_buffer() == end_data() + tailroom() */
|
|
inline const unsigned char *
|
|
Packet::end_buffer() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
return skb_end_pointer(skb());
|
|
# else
|
|
return skb()->end;
|
|
# endif
|
|
#else
|
|
return _end;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the packet's length. */
|
|
inline uint32_t
|
|
Packet::length() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return skb()->len;
|
|
#else
|
|
return _tail - _data;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the packet's headroom.
|
|
*
|
|
* The headroom is the amount of space available in the current packet buffer
|
|
* before data(). A push() operation is cheap if the packet's unshared and
|
|
* the length pushed is less than headroom(). */
|
|
inline uint32_t
|
|
Packet::headroom() const
|
|
{
|
|
return data() - buffer();
|
|
}
|
|
|
|
/** @brief Return the packet's tailroom.
|
|
*
|
|
* The tailroom is the amount of space available in the current packet buffer
|
|
* following end_data(). A put() operation is cheap if the packet's unshared
|
|
* and the length put is less than tailroom(). */
|
|
inline uint32_t
|
|
Packet::tailroom() const
|
|
{
|
|
return end_buffer() - end_data();
|
|
}
|
|
|
|
/** @brief Return the packet's buffer length.
|
|
* @invariant buffer_length() == headroom() + length() + tailroom()
|
|
* @invariant buffer() + buffer_length() == end_buffer() */
|
|
inline uint32_t
|
|
Packet::buffer_length() const
|
|
{
|
|
return end_buffer() - buffer();
|
|
}
|
|
|
|
inline Packet *
|
|
Packet::next() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return (Packet *)(skb()->next);
|
|
#else
|
|
return _aa.next;
|
|
#endif
|
|
}
|
|
|
|
inline Packet *&
|
|
Packet::next()
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return (Packet *&)(skb()->next);
|
|
#else
|
|
return _aa.next;
|
|
#endif
|
|
}
|
|
|
|
inline void
|
|
Packet::set_next(Packet *p)
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
skb()->next = p->skb();
|
|
#else
|
|
_aa.next = p;
|
|
#endif
|
|
}
|
|
|
|
inline Packet *
|
|
Packet::prev() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return (Packet *)(skb()->prev);
|
|
#else
|
|
return _aa.prev;
|
|
#endif
|
|
}
|
|
|
|
inline Packet *&
|
|
Packet::prev()
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return (Packet *&)(skb()->prev);
|
|
#else
|
|
return _aa.prev;
|
|
#endif
|
|
}
|
|
|
|
inline void
|
|
Packet::set_prev(Packet *p)
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
skb()->prev = p->skb();
|
|
#else
|
|
_aa.prev = p;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return true iff the packet's MAC header pointer is set.
|
|
* @sa set_mac_header, clear_mac_header */
|
|
inline bool
|
|
Packet::has_mac_header() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
return skb_mac_header_was_set(skb());
|
|
# else
|
|
return skb()->mac.raw != 0;
|
|
# endif
|
|
#else
|
|
return _aa.mac != 0;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the packet's MAC header pointer.
|
|
* @warning Not useful if !has_mac_header().
|
|
* @sa ether_header, set_mac_header, clear_mac_header, mac_header_length,
|
|
* mac_length */
|
|
inline const unsigned char *
|
|
Packet::mac_header() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
return skb_mac_header(skb());
|
|
# else
|
|
return skb()->mac.raw;
|
|
# endif
|
|
#else
|
|
return _aa.mac;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return true iff the packet's network header pointer is set.
|
|
* @sa set_network_header, clear_network_header */
|
|
inline bool
|
|
Packet::has_network_header() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
# if NET_SKBUFF_DATA_USES_OFFSET
|
|
return skb()->network_header != (network_header_type) ~0U;
|
|
# else
|
|
return skb()->network_header != 0;
|
|
# endif
|
|
# else
|
|
return skb()->nh.raw != 0;
|
|
# endif
|
|
#else
|
|
return _aa.nh != 0;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the packet's network header pointer.
|
|
* @warning Not useful if !has_network_header().
|
|
* @sa ip_header, ip6_header, set_network_header, clear_network_header,
|
|
* network_header_length, network_length */
|
|
inline const unsigned char *
|
|
Packet::network_header() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
return skb_network_header(skb());
|
|
# else
|
|
return skb()->nh.raw;
|
|
# endif
|
|
#else
|
|
return _aa.nh;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return true iff the packet's network header pointer is set.
|
|
* @sa set_network_header, clear_transport_header */
|
|
inline bool
|
|
Packet::has_transport_header() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
# if NET_SKBUFF_DATA_USES_OFFSET
|
|
return skb()->transport_header != (transport_header_type) ~0U;
|
|
# else
|
|
return skb()->transport_header != 0;
|
|
# endif
|
|
# else
|
|
return skb()->h.raw != 0;
|
|
# endif
|
|
#else
|
|
return _aa.h != 0;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the packet's transport header pointer.
|
|
* @warning Not useful if !has_transport_header().
|
|
* @sa tcp_header, udp_header, icmp_header, set_transport_header,
|
|
* clear_transport_header, transport_length */
|
|
inline const unsigned char *
|
|
Packet::transport_header() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
return skb_transport_header(skb());
|
|
# else
|
|
return skb()->h.raw;
|
|
# endif
|
|
#else
|
|
return _aa.h;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the packet's MAC header pointer as Ethernet.
|
|
* @invariant (void *) ether_header() == (void *) mac_header()
|
|
* @warning Not useful if !has_mac_header().
|
|
* @sa mac_header */
|
|
inline const click_ether *
|
|
Packet::ether_header() const
|
|
{
|
|
return reinterpret_cast<const click_ether *>(mac_header());
|
|
}
|
|
|
|
/** @brief Return the packet's network header pointer as IPv4.
|
|
* @invariant (void *) ip_header() == (void *) network_header()
|
|
* @warning Not useful if !has_network_header().
|
|
* @sa network_header */
|
|
inline const click_ip *
|
|
Packet::ip_header() const
|
|
{
|
|
return reinterpret_cast<const click_ip *>(network_header());
|
|
}
|
|
|
|
/** @brief Return the packet's network header pointer as IPv6.
|
|
* @invariant (void *) ip6_header() == (void *) network_header()
|
|
* @warning Not useful if !has_network_header().
|
|
* @sa network_header */
|
|
inline const click_ip6 *
|
|
Packet::ip6_header() const
|
|
{
|
|
return reinterpret_cast<const click_ip6 *>(network_header());
|
|
}
|
|
|
|
/** @brief Return the packet's transport header pointer as ICMP.
|
|
* @invariant (void *) icmp_header() == (void *) transport_header()
|
|
* @warning Not useful if !has_transport_header().
|
|
* @sa transport_header */
|
|
inline const click_icmp *
|
|
Packet::icmp_header() const
|
|
{
|
|
return reinterpret_cast<const click_icmp *>(transport_header());
|
|
}
|
|
|
|
/** @brief Return the packet's transport header pointer as TCP.
|
|
* @invariant (void *) tcp_header() == (void *) transport_header()
|
|
* @warning Not useful if !has_transport_header().
|
|
* @sa transport_header */
|
|
inline const click_tcp *
|
|
Packet::tcp_header() const
|
|
{
|
|
return reinterpret_cast<const click_tcp *>(transport_header());
|
|
}
|
|
|
|
/** @brief Return the packet's transport header pointer as UDP.
|
|
* @invariant (void *) udp_header() == (void *) transport_header()
|
|
* @warning Not useful if !has_transport_header().
|
|
* @sa transport_header */
|
|
inline const click_udp *
|
|
Packet::udp_header() const
|
|
{
|
|
return reinterpret_cast<const click_udp *>(transport_header());
|
|
}
|
|
|
|
/** @brief Return the packet's length starting from its MAC header pointer.
|
|
* @invariant mac_length() == end_data() - mac_header()
|
|
* @warning Not useful if !has_mac_header(). */
|
|
inline int
|
|
Packet::mac_length() const
|
|
{
|
|
return end_data() - mac_header();
|
|
}
|
|
|
|
/** @brief Return the packet's length starting from its network header pointer.
|
|
* @invariant network_length() == end_data() - network_header()
|
|
* @warning Not useful if !has_network_header(). */
|
|
inline int
|
|
Packet::network_length() const
|
|
{
|
|
return end_data() - network_header();
|
|
}
|
|
|
|
/** @brief Return the packet's length starting from its transport header pointer.
|
|
* @invariant transport_length() == end_data() - transport_header()
|
|
* @warning Not useful if !has_transport_header(). */
|
|
inline int
|
|
Packet::transport_length() const
|
|
{
|
|
return end_data() - transport_header();
|
|
}
|
|
|
|
inline const Timestamp&
|
|
Packet::timestamp_anno() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 13)
|
|
return *reinterpret_cast<const Timestamp*>(&skb()->stamp);
|
|
# else
|
|
return *reinterpret_cast<const Timestamp*>(&skb()->tstamp);
|
|
# endif
|
|
#else
|
|
return *reinterpret_cast<const Timestamp*>(&_aa.timestamp);
|
|
#endif
|
|
}
|
|
|
|
inline Timestamp&
|
|
Packet::timestamp_anno()
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 13)
|
|
return *reinterpret_cast<Timestamp*>(&skb()->stamp);
|
|
# else
|
|
return *reinterpret_cast<Timestamp*>(&skb()->tstamp);
|
|
# endif
|
|
#else
|
|
return *reinterpret_cast<Timestamp*>(&_aa.timestamp);
|
|
#endif
|
|
}
|
|
|
|
inline void
|
|
Packet::set_timestamp_anno(const Timestamp ×tamp)
|
|
{
|
|
timestamp_anno() = timestamp;
|
|
}
|
|
|
|
inline net_device *
|
|
Packet::device_anno() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return skb()->dev;
|
|
#elif CLICK_BSDMODULE
|
|
if (m())
|
|
return m()->m_pkthdr.rcvif;
|
|
else
|
|
return 0;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
inline void
|
|
Packet::set_device_anno(net_device *dev)
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
skb()->dev = dev;
|
|
#elif CLICK_BSDMODULE
|
|
if (m())
|
|
m()->m_pkthdr.rcvif = dev;
|
|
#else
|
|
(void) dev;
|
|
#endif
|
|
}
|
|
|
|
inline Packet::PacketType
|
|
Packet::packet_type_anno() const
|
|
{
|
|
#if CLICK_LINUXMODULE && PACKET_TYPE_MASK
|
|
return (PacketType)(skb()->pkt_type & PACKET_TYPE_MASK);
|
|
#elif CLICK_LINUXMODULE
|
|
return (PacketType)(skb()->pkt_type);
|
|
#else
|
|
return _aa.pkt_type;
|
|
#endif
|
|
}
|
|
|
|
inline void
|
|
Packet::set_packet_type_anno(PacketType p)
|
|
{
|
|
#if CLICK_LINUXMODULE && PACKET_TYPE_MASK
|
|
skb()->pkt_type = (skb()->pkt_type & PACKET_CLEAN) | p;
|
|
#elif CLICK_LINUXMODULE
|
|
skb()->pkt_type = p;
|
|
#else
|
|
_aa.pkt_type = p;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Create and return a new packet.
|
|
* @param data data to be copied into the new packet
|
|
* @param length length of packet
|
|
* @return new packet, or null if no packet could be created
|
|
*
|
|
* The @a data is copied into the new packet. If @a data is null, the
|
|
* packet's data is left uninitialized. The new packet's headroom equals
|
|
* @link Packet::default_headroom default_headroom @endlink, its tailroom is 0.
|
|
*
|
|
* The returned packet's annotations are cleared and its header pointers are
|
|
* null. */
|
|
inline WritablePacket *
|
|
Packet::make(const void *data, uint32_t length)
|
|
{
|
|
return make(default_headroom, data, length, 0);
|
|
}
|
|
|
|
/** @brief Create and return a new packet.
|
|
* @param length length of packet
|
|
* @return new packet, or null if no packet could be created
|
|
*
|
|
* The packet's data is left uninitialized. The new packet's headroom equals
|
|
* @link Packet::default_headroom default_headroom @endlink, its tailroom is 0.
|
|
*
|
|
* The returned packet's annotations are cleared and its header pointers are
|
|
* null. */
|
|
inline WritablePacket *
|
|
Packet::make(uint32_t length)
|
|
{
|
|
return make(default_headroom, (const unsigned char *) 0, length, 0);
|
|
}
|
|
|
|
#if CLICK_LINUXMODULE
|
|
/** @brief Change an sk_buff into a Packet (linuxmodule).
|
|
* @param skb input sk_buff
|
|
* @return the packet
|
|
*
|
|
* In the Linux kernel module, Packet objects are sk_buff objects. This
|
|
* function simply changes an sk_buff into a Packet by claiming its @a skb
|
|
* argument. If <tt>skb->users</tt> is 1, then @a skb is orphaned by
|
|
* <tt>skb_orphan(skb)</tt> and returned. If it is larger than 1, then @a skb
|
|
* is cloned and the clone is returned. (sk_buffs used for Click Packet
|
|
* objects must have <tt>skb->users</tt> == 1.) Null might be returned if
|
|
* there's no memory for the clone.
|
|
*
|
|
* The returned packet's annotations and header pointers <em>are not
|
|
* cleared</em>: they have the same values they did in the sk_buff. If the
|
|
* packet came from Linux, then the header pointers and shared annotations
|
|
* (timestamp, packet type, next/prev packet) might have valid values, but the
|
|
* Click annotations (address, user) likely do not. Use clear_annotations()
|
|
* to clear them. */
|
|
inline Packet *
|
|
Packet::make(struct sk_buff *skb)
|
|
{
|
|
struct sk_buff *nskb;
|
|
if (atomic_read(&skb->users) == 1) {
|
|
skb_orphan(skb);
|
|
nskb = skb;
|
|
} else {
|
|
nskb = skb_clone(skb, GFP_ATOMIC);
|
|
atomic_dec(&skb->users);
|
|
}
|
|
# if HAVE_SKB_LINEARIZE
|
|
# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
|
|
if (nskb && skb_linearize(nskb, GFP_ATOMIC) != 0)
|
|
# else
|
|
if (nskb && skb_linearize(nskb) != 0)
|
|
# endif
|
|
{
|
|
kfree_skb(nskb);
|
|
nskb = 0;
|
|
}
|
|
# endif
|
|
return reinterpret_cast<Packet *>(nskb);
|
|
}
|
|
#endif
|
|
|
|
/** @brief Delete this packet.
|
|
*
|
|
* The packet header (including annotations) is destroyed and its memory
|
|
* returned to the system. The packet's data is also freed if this is the
|
|
* last clone. */
|
|
inline void
|
|
Packet::kill()
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
struct sk_buff *b = skb();
|
|
b->next = b->prev = 0;
|
|
# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
|
|
b->list = 0;
|
|
# endif
|
|
skbmgr_recycle_skbs(b);
|
|
#elif HAVE_CLICK_PACKET_POOL
|
|
if (_use_count.dec_and_test())
|
|
WritablePacket::recycle(static_cast<WritablePacket *>(this));
|
|
#else
|
|
if (_use_count.dec_and_test())
|
|
delete this;
|
|
#endif
|
|
}
|
|
|
|
#if CLICK_BSDMODULE /* BSD kernel module */
|
|
inline void
|
|
Packet::assimilate_mbuf(Packet *p)
|
|
{
|
|
struct mbuf *m = p->m();
|
|
|
|
if (!m) return;
|
|
|
|
p->_head = (unsigned char *)
|
|
(m->m_flags & M_EXT ? m->m_ext.ext_buf :
|
|
m->m_flags & M_PKTHDR ? m->m_pktdat :
|
|
m->m_dat);
|
|
p->_data = (unsigned char *)m->m_data;
|
|
p->_tail = (unsigned char *)(m->m_data + m->m_len);
|
|
p->_end = p->_head +
|
|
(m->m_flags & M_EXT ? min(m->m_pkthdr.len, m->m_ext.ext_size) :
|
|
m->m_flags & M_PKTHDR ? MHLEN :
|
|
MLEN);
|
|
}
|
|
|
|
inline void
|
|
Packet::assimilate_mbuf()
|
|
{
|
|
assimilate_mbuf(this);
|
|
}
|
|
|
|
inline Packet *
|
|
Packet::make(struct mbuf *m)
|
|
{
|
|
if (!(m->m_flags & M_PKTHDR))
|
|
panic("trying to construct Packet from a non-packet mbuf");
|
|
|
|
Packet *p = new Packet;
|
|
if (!p) {
|
|
m_freem(m);
|
|
return 0;
|
|
}
|
|
p->_use_count = 1;
|
|
p->_data_packet = NULL;
|
|
|
|
if (m->m_pkthdr.len != m->m_len) {
|
|
struct mbuf *m2;
|
|
/* click needs contiguous data */
|
|
|
|
if (m->m_pkthdr.len <= MCLBYTES) {
|
|
// click_chatter("m_pulldown, Click needs contiguous data");
|
|
m2 = m_pulldown(m, 0, m->m_pkthdr.len, NULL);
|
|
if (m2 == NULL)
|
|
panic("m_pulldown failed");
|
|
if (m2 != m) {
|
|
/*
|
|
* XXX: m_pulldown ensures that the data is contiguous, but
|
|
* it's not necessarily in the first mbuf in the chain.
|
|
* Currently that's not OK for Click, so we need to
|
|
* defragment the mbuf - which involves more copying etc.
|
|
*/
|
|
m2 = m_defrag(m, M_DONTWAIT);
|
|
if (m2 == NULL) {
|
|
m_freem(m);
|
|
delete p;
|
|
return 0;
|
|
}
|
|
m = m2;
|
|
}
|
|
} else {
|
|
m2 = p->dup_jumbo_m(m);
|
|
m_freem(m);
|
|
if (m2 == NULL) {
|
|
delete p;
|
|
return 0;
|
|
}
|
|
m = m2;
|
|
}
|
|
}
|
|
p->_m = m;
|
|
assimilate_mbuf(p);
|
|
|
|
return p;
|
|
}
|
|
#endif
|
|
|
|
/** @brief Test whether this packet's data is shared.
|
|
*
|
|
* Returns true iff the packet's data is shared. If shared() is false, then
|
|
* the result of uniqueify() will equal @c this. */
|
|
inline bool
|
|
Packet::shared() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return skb_cloned(const_cast<struct sk_buff *>(skb()));
|
|
#else
|
|
return (_data_packet || _use_count > 1);
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return an unshared packet containing this packet's data.
|
|
* @return the unshared packet, which is writable
|
|
*
|
|
* The returned packet's data is unshared with any other packet, so it's safe
|
|
* to write the data. If shared() is false, this operation simply returns the
|
|
* input packet. If shared() is true, uniqueify() makes a copy of the data.
|
|
* The input packet is freed if the copy fails.
|
|
*
|
|
* The returned WritablePacket pointer may not equal the input Packet pointer,
|
|
* so do not use the input pointer after the uniqueify() call.
|
|
*
|
|
* The input packet's headroom and tailroom areas are copied in addition to
|
|
* its true contents. The header annotations are shifted to point into the
|
|
* new packet data if necessary.
|
|
*
|
|
* uniqueify() is usually used like this:
|
|
* @code
|
|
* WritablePacket *q = p->uniqueify();
|
|
* if (!q)
|
|
* return 0;
|
|
* // p must not be used here.
|
|
* @endcode
|
|
*/
|
|
inline WritablePacket *
|
|
Packet::uniqueify()
|
|
{
|
|
if (!shared())
|
|
return static_cast<WritablePacket *>(this);
|
|
else
|
|
return expensive_uniqueify(0, 0, true);
|
|
}
|
|
|
|
inline WritablePacket *
|
|
Packet::push(uint32_t len)
|
|
{
|
|
if (headroom() >= len && !shared()) {
|
|
WritablePacket *q = (WritablePacket *)this;
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
__skb_push(q->skb(), len);
|
|
#else /* User-space and BSD kernel module */
|
|
q->_data -= len;
|
|
# if CLICK_BSDMODULE
|
|
q->m()->m_data -= len;
|
|
q->m()->m_len += len;
|
|
q->m()->m_pkthdr.len += len;
|
|
# endif
|
|
#endif
|
|
return q;
|
|
} else
|
|
return expensive_push(len);
|
|
}
|
|
|
|
inline Packet *
|
|
Packet::nonunique_push(uint32_t len)
|
|
{
|
|
if (headroom() >= len) {
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
__skb_push(skb(), len);
|
|
#else /* User-space and BSD kernel module */
|
|
_data -= len;
|
|
# if CLICK_BSDMODULE
|
|
m()->m_data -= len;
|
|
m()->m_len += len;
|
|
m()->m_pkthdr.len += len;
|
|
# endif
|
|
#endif
|
|
return this;
|
|
} else
|
|
return expensive_push(len);
|
|
}
|
|
|
|
inline void
|
|
Packet::pull(uint32_t len)
|
|
{
|
|
if (len > length()) {
|
|
click_chatter("Packet::pull %d > length %d\n", len, length());
|
|
len = length();
|
|
}
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
__skb_pull(skb(), len);
|
|
#else /* User-space and BSD kernel module */
|
|
_data += len;
|
|
# if CLICK_BSDMODULE
|
|
m()->m_data += len;
|
|
m()->m_len -= len;
|
|
m()->m_pkthdr.len -= len;
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
inline WritablePacket *
|
|
Packet::put(uint32_t len)
|
|
{
|
|
if (tailroom() >= len && !shared()) {
|
|
WritablePacket *q = (WritablePacket *)this;
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
__skb_put(q->skb(), len);
|
|
#else /* User-space and BSD kernel module */
|
|
q->_tail += len;
|
|
# if CLICK_BSDMODULE
|
|
q->m()->m_len += len;
|
|
q->m()->m_pkthdr.len += len;
|
|
# endif
|
|
#endif
|
|
return q;
|
|
} else
|
|
return expensive_put(len);
|
|
}
|
|
|
|
inline Packet *
|
|
Packet::nonunique_put(uint32_t len)
|
|
{
|
|
if (tailroom() >= len) {
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
__skb_put(skb(), len);
|
|
#else /* User-space and BSD kernel module */
|
|
_tail += len;
|
|
# if CLICK_BSDMODULE
|
|
m()->m_len += len;
|
|
m()->m_pkthdr.len += len;
|
|
# endif
|
|
#endif
|
|
return this;
|
|
} else
|
|
return expensive_put(len);
|
|
}
|
|
|
|
inline void
|
|
Packet::take(uint32_t len)
|
|
{
|
|
if (len > length()) {
|
|
click_chatter("Packet::take %d > length %d\n", len, length());
|
|
len = length();
|
|
}
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
skb()->tail -= len;
|
|
skb()->len -= len;
|
|
#else /* User-space and BSD kernel module */
|
|
_tail -= len;
|
|
# if CLICK_BSDMODULE
|
|
m()->m_len -= len;
|
|
m()->m_pkthdr.len -= len;
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
#if CLICK_USERLEVEL || CLICK_MINIOS
|
|
/** @brief Shrink the packet's data.
|
|
* @param data new data pointer
|
|
* @param length new length
|
|
*
|
|
* @warning This function is useful only in special contexts.
|
|
* @note Only available at user level
|
|
*
|
|
* User-level programs that read packet logs commonly read a large chunk of
|
|
* data (32 kB or more) into a base Packet object. The log reader then works
|
|
* over the data buffer and, for each packet contained therein, outputs a
|
|
* clone that shares memory with the base packet. This is space- and
|
|
* time-efficient, but the generated packets have gigantic headroom and
|
|
* tailroom. Uniqueifying a generated packet will wastefully copy this
|
|
* headroom and tailroom as well. The shrink_data function addresses this
|
|
* problem.
|
|
*
|
|
* shrink_data() removes all of a packet's headroom and tailroom. The
|
|
* resulting packet has data() equal to @a data, length() equal to @a length,
|
|
* and headroom() and tailroom() equal to zero.
|
|
*
|
|
* @pre The packet @em must be a clone() of another existing packet.
|
|
* @pre @a data >= data(), @a data <= end_data(), @a data + @a length >=
|
|
* data(), and @a data + @a length <= end_data()
|
|
*
|
|
* @sa change_headroom_and_length */
|
|
inline void
|
|
Packet::shrink_data(const unsigned char *data, uint32_t length)
|
|
{
|
|
assert(_data_packet);
|
|
if (data >= _head && data + length >= data && data + length <= _end) {
|
|
_head = _data = const_cast<unsigned char *>(data);
|
|
_tail = _end = const_cast<unsigned char *>(data + length);
|
|
}
|
|
}
|
|
|
|
/** @brief Shift the packet's data view to a different part of its buffer.
|
|
* @param headroom new headroom
|
|
* @param length new length
|
|
*
|
|
* @warning This function is useful only in special contexts.
|
|
* @note Only available at user level
|
|
*
|
|
* Shifts the packet's data() pointer to a different part of the packet's data
|
|
* buffer. The buffer pointer itself is not changed, and the packet's
|
|
* contents are not affected (except by the new view).
|
|
*
|
|
* @pre @a headroom + @a length <= buffer_length()
|
|
* @post new buffer() == old buffer()
|
|
* @post new end_buffer() == old end_buffer()
|
|
* @post new headroom() == @a headroom
|
|
* @post new length() == @a length
|
|
*
|
|
* @sa shrink_data */
|
|
inline void
|
|
Packet::change_headroom_and_length(uint32_t headroom, uint32_t length)
|
|
{
|
|
if (headroom + length <= buffer_length()) {
|
|
_data = _head + headroom;
|
|
_tail = _data + length;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
inline IPAddress
|
|
Packet::dst_ip_anno() const
|
|
{
|
|
return IPAddress(xanno()->u32[dst_ip_anno_offset / 4]);
|
|
}
|
|
|
|
inline void
|
|
Packet::set_dst_ip_anno(IPAddress a)
|
|
{
|
|
xanno()->u32[dst_ip_anno_offset / 4] = a.addr();
|
|
}
|
|
|
|
/** @brief Set the MAC header pointer.
|
|
* @param p new header pointer */
|
|
inline void
|
|
Packet::set_mac_header(const unsigned char *p)
|
|
{
|
|
assert(p >= buffer() && p <= end_buffer());
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
skb_set_mac_header(skb(), p - data());
|
|
# else
|
|
skb()->mac.raw = const_cast<unsigned char *>(p);
|
|
# endif
|
|
#else /* User-space and BSD kernel module */
|
|
_aa.mac = const_cast<unsigned char *>(p);
|
|
#endif
|
|
}
|
|
|
|
/** @brief Set the MAC and network header pointers.
|
|
* @param p new MAC header pointer
|
|
* @param len new MAC header length
|
|
* @post mac_header() == @a p and network_header() == @a p + @a len */
|
|
inline void
|
|
Packet::set_mac_header(const unsigned char *p, uint32_t len)
|
|
{
|
|
assert(p >= buffer() && p + len <= end_buffer());
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
skb_set_mac_header(skb(), p - data());
|
|
skb_set_network_header(skb(), (p + len) - data());
|
|
# else
|
|
skb()->mac.raw = const_cast<unsigned char *>(p);
|
|
skb()->nh.raw = const_cast<unsigned char *>(p) + len;
|
|
# endif
|
|
#else /* User-space and BSD kernel module */
|
|
_aa.mac = const_cast<unsigned char *>(p);
|
|
_aa.nh = const_cast<unsigned char *>(p) + len;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Set the MAC header pointer to an Ethernet header.
|
|
* @param ethh new Ethernet header pointer
|
|
* @post (void *) mac_header() == (void *) @a ethh
|
|
* @post mac_header_length() == 14
|
|
* @post (void *) network_header() == (void *) (@a ethh + 1) */
|
|
inline void
|
|
Packet::set_ether_header(const click_ether *ethh)
|
|
{
|
|
set_mac_header(reinterpret_cast<const unsigned char *>(ethh), 14);
|
|
}
|
|
|
|
/** @brief Unset the MAC header pointer.
|
|
* @post has_mac_header() == false
|
|
* Does not affect the network or transport header pointers. */
|
|
inline void
|
|
Packet::clear_mac_header()
|
|
{
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && NET_SKBUFF_DATA_USES_OFFSET
|
|
skb()->mac_header = (mac_header_type) ~0U;
|
|
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
skb()->mac_header = 0;
|
|
# else
|
|
skb()->mac.raw = 0;
|
|
# endif
|
|
#else /* User-space and BSD kernel module */
|
|
_aa.mac = 0;
|
|
#endif
|
|
}
|
|
|
|
inline WritablePacket *
|
|
Packet::push_mac_header(uint32_t len)
|
|
{
|
|
WritablePacket *q;
|
|
if (headroom() >= len && !shared()) {
|
|
q = (WritablePacket *)this;
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
__skb_push(q->skb(), len);
|
|
#else /* User-space and BSD kernel module */
|
|
q->_data -= len;
|
|
# if CLICK_BSDMODULE
|
|
q->m()->m_data -= len;
|
|
q->m()->m_len += len;
|
|
q->m()->m_pkthdr.len += len;
|
|
# endif
|
|
#endif
|
|
} else if ((q = expensive_push(len)))
|
|
/* nada */;
|
|
else
|
|
return 0;
|
|
q->set_mac_header(q->data(), len);
|
|
return q;
|
|
}
|
|
|
|
/** @brief Set the network and transport header pointers.
|
|
* @param p new network header pointer
|
|
* @param len new network header length
|
|
* @post network_header() == @a p and transport_header() == @a p + @a len */
|
|
inline void
|
|
Packet::set_network_header(const unsigned char *p, uint32_t len)
|
|
{
|
|
assert(p >= buffer() && p + len <= end_buffer());
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
skb_set_network_header(skb(), p - data());
|
|
skb_set_transport_header(skb(), (p + len) - data());
|
|
# else
|
|
skb()->nh.raw = const_cast<unsigned char *>(p);
|
|
skb()->h.raw = const_cast<unsigned char *>(p) + len;
|
|
# endif
|
|
#else /* User-space and BSD kernel module */
|
|
_aa.nh = const_cast<unsigned char *>(p);
|
|
_aa.h = const_cast<unsigned char *>(p) + len;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Set the network header length.
|
|
* @param len new network header length
|
|
*
|
|
* Setting the network header length really just sets the transport header
|
|
* pointer.
|
|
* @post transport_header() == network_header() + @a len */
|
|
inline void
|
|
Packet::set_network_header_length(uint32_t len)
|
|
{
|
|
assert(network_header() + len <= end_buffer());
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
skb_set_transport_header(skb(), (network_header() + len) - data());
|
|
# else
|
|
skb()->h.raw = skb()->nh.raw + len;
|
|
# endif
|
|
#else /* User-space and BSD kernel module */
|
|
_aa.h = _aa.nh + len;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Set the network header pointer to an IPv4 header.
|
|
* @param iph new IP header pointer
|
|
* @param len new IP header length in bytes
|
|
* @post (char *) network_header() == (char *) @a iph
|
|
* @post network_header_length() == @a len
|
|
* @post (char *) transport_header() == (char *) @a iph + @a len */
|
|
inline void
|
|
Packet::set_ip_header(const click_ip *iph, uint32_t len)
|
|
{
|
|
set_network_header(reinterpret_cast<const unsigned char *>(iph), len);
|
|
}
|
|
|
|
/** @brief Set the network header pointer to an IPv6 header.
|
|
* @param ip6h new IP header pointer
|
|
* @param len new IP header length in bytes
|
|
* @post (char *) network_header() == (char *) @a ip6h
|
|
* @post network_header_length() == @a len
|
|
* @post (char *) transport_header() == (char *) @a ip6h + @a len */
|
|
inline void
|
|
Packet::set_ip6_header(const click_ip6 *ip6h, uint32_t len)
|
|
{
|
|
set_network_header(reinterpret_cast<const unsigned char *>(ip6h), len);
|
|
}
|
|
|
|
/** @brief Set the network header pointer to an IPv6 header.
|
|
* @param ip6h new IP header pointer
|
|
* @post (char *) network_header() == (char *) @a ip6h
|
|
* @post network_header_length() == 40
|
|
* @post (char *) transport_header() == (char *) (@a ip6h + 1) */
|
|
inline void
|
|
Packet::set_ip6_header(const click_ip6 *ip6h)
|
|
{
|
|
set_ip6_header(ip6h, 40);
|
|
}
|
|
|
|
/** @brief Unset the network header pointer.
|
|
* @post has_network_header() == false
|
|
* Does not affect the MAC or transport header pointers. */
|
|
inline void
|
|
Packet::clear_network_header()
|
|
{
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && NET_SKBUFF_DATA_USES_OFFSET
|
|
skb()->network_header = (network_header_type) ~0U;
|
|
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
skb()->network_header = 0;
|
|
# else
|
|
skb()->nh.raw = 0;
|
|
# endif
|
|
#else /* User-space and BSD kernel module */
|
|
_aa.nh = 0;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return the offset from the packet data to the MAC header.
|
|
* @return mac_header() - data()
|
|
* @warning Not useful if !has_mac_header(). */
|
|
inline int
|
|
Packet::mac_header_offset() const
|
|
{
|
|
return mac_header() - data();
|
|
}
|
|
|
|
/** @brief Return the MAC header length.
|
|
* @return network_header() - mac_header()
|
|
*
|
|
* This equals the offset from the MAC header pointer to the network header
|
|
* pointer.
|
|
* @warning Not useful if !has_mac_header() or !has_network_header(). */
|
|
inline uint32_t
|
|
Packet::mac_header_length() const
|
|
{
|
|
return network_header() - mac_header();
|
|
}
|
|
|
|
/** @brief Return the offset from the packet data to the network header.
|
|
* @return network_header() - data()
|
|
* @warning Not useful if !has_network_header(). */
|
|
inline int
|
|
Packet::network_header_offset() const
|
|
{
|
|
return network_header() - data();
|
|
}
|
|
|
|
/** @brief Return the network header length.
|
|
* @return transport_header() - network_header()
|
|
*
|
|
* This equals the offset from the network header pointer to the transport
|
|
* header pointer.
|
|
* @warning Not useful if !has_network_header() or !has_transport_header(). */
|
|
inline uint32_t
|
|
Packet::network_header_length() const
|
|
{
|
|
return transport_header() - network_header();
|
|
}
|
|
|
|
/** @brief Return the offset from the packet data to the IP header.
|
|
* @return network_header() - mac_header()
|
|
* @warning Not useful if !has_network_header().
|
|
* @sa network_header_offset */
|
|
inline int
|
|
Packet::ip_header_offset() const
|
|
{
|
|
return network_header_offset();
|
|
}
|
|
|
|
/** @brief Return the IP header length.
|
|
* @return transport_header() - network_header()
|
|
*
|
|
* This equals the offset from the network header pointer to the transport
|
|
* header pointer.
|
|
* @warning Not useful if !has_network_header() or !has_transport_header().
|
|
* @sa network_header_length */
|
|
inline uint32_t
|
|
Packet::ip_header_length() const
|
|
{
|
|
return network_header_length();
|
|
}
|
|
|
|
/** @brief Return the offset from the packet data to the IPv6 header.
|
|
* @return network_header() - data()
|
|
* @warning Not useful if !has_network_header().
|
|
* @sa network_header_offset */
|
|
inline int
|
|
Packet::ip6_header_offset() const
|
|
{
|
|
return network_header_offset();
|
|
}
|
|
|
|
/** @brief Return the IPv6 header length.
|
|
* @return transport_header() - network_header()
|
|
*
|
|
* This equals the offset from the network header pointer to the transport
|
|
* header pointer.
|
|
* @warning Not useful if !has_network_header() or !has_transport_header().
|
|
* @sa network_header_length */
|
|
inline uint32_t
|
|
Packet::ip6_header_length() const
|
|
{
|
|
return network_header_length();
|
|
}
|
|
|
|
/** @brief Return the offset from the packet data to the transport header.
|
|
* @return transport_header() - data()
|
|
* @warning Not useful if !has_transport_header(). */
|
|
inline int
|
|
Packet::transport_header_offset() const
|
|
{
|
|
return transport_header() - data();
|
|
}
|
|
|
|
/** @brief Unset the transport header pointer.
|
|
* @post has_transport_header() == false
|
|
* Does not affect the MAC or network header pointers. */
|
|
inline void
|
|
Packet::clear_transport_header()
|
|
{
|
|
#if CLICK_LINUXMODULE /* Linux kernel module */
|
|
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && NET_SKBUFF_DATA_USES_OFFSET
|
|
skb()->transport_header = (transport_header_type) ~0U;
|
|
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
skb()->transport_header = 0;
|
|
# else
|
|
skb()->h.raw = 0;
|
|
# endif
|
|
#else /* User-space and BSD kernel module */
|
|
_aa.h = 0;
|
|
#endif
|
|
}
|
|
|
|
inline void
|
|
Packet::shift_header_annotations(const unsigned char *old_head,
|
|
int32_t extra_headroom)
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
struct sk_buff *mskb = skb();
|
|
/* From Linux 2.6.24 - 3.10, the header offsets are integers if
|
|
* NET_SKBUFF_DATA_USES_OFFSET is 1. From 3.11 onward, they're
|
|
* always integers. */
|
|
# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && NET_SKBUFF_DATA_USES_OFFSET) || \
|
|
(LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
|
|
(void) old_head;
|
|
mskb->mac_header += (mskb->mac_header == (mac_header_type) ~0U ? 0 : extra_headroom);
|
|
mskb->network_header += (mskb->network_header == (network_header_type) ~0U ? 0 : extra_headroom);
|
|
mskb->transport_header += (mskb->transport_header == (transport_header_type) ~0U ? 0 : extra_headroom);
|
|
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
|
ptrdiff_t shift = (mskb->head - old_head) + extra_headroom;
|
|
mskb->mac_header += (mskb->mac_header ? shift : 0);
|
|
mskb->network_header += (mskb->network_header ? shift : 0);
|
|
mskb->transport_header += (mskb->transport_header ? shift : 0);
|
|
# else
|
|
ptrdiff_t shift = (mskb->head - old_head) + extra_headroom;
|
|
mskb->mac.raw += (mskb->mac.raw ? shift : 0);
|
|
mskb->nh.raw += (mskb->nh.raw ? shift : 0);
|
|
mskb->h.raw += (mskb->h.raw ? shift : 0);
|
|
# endif
|
|
#else
|
|
ptrdiff_t shift = (_head - old_head) + extra_headroom;
|
|
_aa.mac += (_aa.mac ? shift : 0);
|
|
_aa.nh += (_aa.nh ? shift : 0);
|
|
_aa.h += (_aa.h ? shift : 0);
|
|
#endif
|
|
}
|
|
|
|
/** @cond never */
|
|
/** @brief Return a pointer to the packet's data buffer.
|
|
* @deprecated Use buffer() instead. */
|
|
inline const unsigned char *
|
|
Packet::buffer_data() const
|
|
{
|
|
#if CLICK_LINUXMODULE
|
|
return skb()->head;
|
|
#else
|
|
return _head;
|
|
#endif
|
|
}
|
|
|
|
/** @brief Return a pointer to the address annotation area.
|
|
* @deprecated Use anno() instead.
|
|
*
|
|
* The area is ADDR_ANNO_SIZE bytes long. */
|
|
inline void *Packet::addr_anno() {
|
|
return anno_u8() + addr_anno_offset;
|
|
}
|
|
|
|
/** @overload */
|
|
inline const void *Packet::addr_anno() const {
|
|
return anno_u8() + addr_anno_offset;
|
|
}
|
|
|
|
/** @brief Return a pointer to the user annotation area.
|
|
* @deprecated Use Packet::anno() instead.
|
|
*
|
|
* The area is USER_ANNO_SIZE bytes long. */
|
|
inline void *Packet::user_anno() {
|
|
return anno_u8() + user_anno_offset;
|
|
}
|
|
|
|
/** @overload */
|
|
inline const void *Packet::user_anno() const {
|
|
return anno_u8() + user_anno_offset;
|
|
}
|
|
|
|
/** @brief Return a pointer to the user annotation area as uint8_ts.
|
|
* @deprecated Use Packet::anno_u8() instead. */
|
|
inline uint8_t *Packet::user_anno_u8() {
|
|
return anno_u8() + user_anno_offset;
|
|
}
|
|
|
|
/** @brief overload */
|
|
inline const uint8_t *Packet::user_anno_u8() const {
|
|
return anno_u8() + user_anno_offset;
|
|
}
|
|
|
|
/** @brief Return a pointer to the user annotation area as uint32_ts.
|
|
* @deprecated Use Packet::anno_u32() instead. */
|
|
inline uint32_t *Packet::user_anno_u32() {
|
|
return anno_u32() + user_anno_offset / 4;
|
|
}
|
|
|
|
/** @brief overload */
|
|
inline const uint32_t *Packet::user_anno_u32() const {
|
|
return anno_u32() + user_anno_offset / 4;
|
|
}
|
|
|
|
/** @brief Return user annotation byte @a i.
|
|
* @param i annotation index
|
|
* @pre 0 <= @a i < USER_ANNO_SIZE
|
|
* @deprecated Use Packet::anno_u8(@a i) instead. */
|
|
inline uint8_t Packet::user_anno_u8(int i) const {
|
|
return anno_u8(user_anno_offset + i);
|
|
}
|
|
|
|
/** @brief Set user annotation byte @a i.
|
|
* @param i annotation index
|
|
* @param v value
|
|
* @pre 0 <= @a i < USER_ANNO_SIZE
|
|
* @deprecated Use Packet::set_anno_u8(@a i, @a v) instead. */
|
|
inline void Packet::set_user_anno_u8(int i, uint8_t v) {
|
|
set_anno_u8(user_anno_offset + i, v);
|
|
}
|
|
|
|
/** @brief Return 16-bit user annotation @a i.
|
|
* @param i annotation index
|
|
* @pre 0 <= @a i < USER_ANNO_U16_SIZE
|
|
* @deprecated Use Packet::anno_u16(@a i * 2) instead.
|
|
*
|
|
* Affects user annotation bytes [2*@a i, 2*@a i+1]. */
|
|
inline uint16_t Packet::user_anno_u16(int i) const {
|
|
return anno_u16(user_anno_offset + i * 2);
|
|
}
|
|
|
|
/** @brief Set 16-bit user annotation @a i.
|
|
* @param i annotation index
|
|
* @param v value
|
|
* @pre 0 <= @a i < USER_ANNO_U16_SIZE
|
|
* @deprecated Use Packet::set_anno_u16(@a i * 2, @a v) instead.
|
|
*
|
|
* Affects user annotation bytes [2*@a i, 2*@a i+1]. */
|
|
inline void Packet::set_user_anno_u16(int i, uint16_t v) {
|
|
set_anno_u16(user_anno_offset + i * 2, v);
|
|
}
|
|
|
|
/** @brief Return 32-bit user annotation @a i.
|
|
* @param i annotation index
|
|
* @pre 0 <= @a i < USER_ANNO_U32_SIZE
|
|
* @deprecated Use Packet::anno_u32(@a i * 4) instead.
|
|
*
|
|
* Affects user annotation bytes [4*@a i, 4*@a i+3]. */
|
|
inline uint32_t Packet::user_anno_u32(int i) const {
|
|
return anno_u32(user_anno_offset + i * 4);
|
|
}
|
|
|
|
/** @brief Set 32-bit user annotation @a i.
|
|
* @param i annotation index
|
|
* @param v value
|
|
* @pre 0 <= @a i < USER_ANNO_U32_SIZE
|
|
* @deprecated Use Packet::set_anno_u32(@a i * 4, @a v) instead.
|
|
*
|
|
* Affects user annotation bytes [4*@a i, 4*@a i+3]. */
|
|
inline void Packet::set_user_anno_u32(int i, uint32_t v) {
|
|
set_anno_u32(user_anno_offset + i * 4, v);
|
|
}
|
|
|
|
/** @brief Return 32-bit user annotation @a i.
|
|
* @param i annotation index
|
|
* @pre 0 <= @a i < USER_ANNO_U32_SIZE
|
|
* @deprecated Use Packet::anno_s32(@a i * 4) instead.
|
|
*
|
|
* Affects user annotation bytes [4*@a i, 4*@a i+3]. */
|
|
inline int32_t Packet::user_anno_s32(int i) const {
|
|
return anno_s32(user_anno_offset + i * 4);
|
|
}
|
|
|
|
/** @brief Set 32-bit user annotation @a i.
|
|
* @param i annotation index
|
|
* @param v value
|
|
* @pre 0 <= @a i < USER_ANNO_U32_SIZE
|
|
* @deprecated Use Packet::set_anno_s32(@a i * 4, @a v) instead.
|
|
*
|
|
* Affects user annotation bytes [4*@a i, 4*@a i+3]. */
|
|
inline void Packet::set_user_anno_s32(int i, int32_t v) {
|
|
set_anno_s32(user_anno_offset + i * 4, v);
|
|
}
|
|
|
|
#if HAVE_INT64_TYPES
|
|
/** @brief Return 64-bit user annotation @a i.
|
|
* @param i annotation index
|
|
* @pre 0 <= @a i < USER_ANNO_U64_SIZE
|
|
* @deprecated Use Packet::anno_u64(@a i * 8) instead.
|
|
*
|
|
* Affects user annotation bytes [8*@a i, 8*@a i+7]. */
|
|
inline uint64_t Packet::user_anno_u64(int i) const {
|
|
return anno_u64(user_anno_offset + i * 8);
|
|
}
|
|
|
|
/** @brief Set 64-bit user annotation @a i.
|
|
* @param i annotation index
|
|
* @param v value
|
|
* @pre 0 <= @a i < USER_ANNO_U64_SIZE
|
|
* @deprecated Use Packet::set_anno_u64(@a i * 8, @a v) instead.
|
|
*
|
|
* Affects user annotation bytes [8*@a i, 8*@a i+7]. */
|
|
inline void Packet::set_user_anno_u64(int i, uint64_t v) {
|
|
set_anno_u64(user_anno_offset + i * 8, v);
|
|
}
|
|
#endif
|
|
|
|
/** @brief Return a pointer to the user annotation area.
|
|
* @deprecated Use anno() instead. */
|
|
inline const uint8_t *Packet::all_user_anno() const {
|
|
return anno_u8() + user_anno_offset;
|
|
}
|
|
|
|
/** @overload
|
|
* @deprecated Use anno() instead. */
|
|
inline uint8_t *Packet::all_user_anno() {
|
|
return anno_u8() + user_anno_offset;
|
|
}
|
|
|
|
/** @brief Return a pointer to the user annotation area as uint32_ts.
|
|
* @deprecated Use anno_u32() instead. */
|
|
inline const uint32_t *Packet::all_user_anno_u() const {
|
|
return anno_u32() + user_anno_offset / 4;
|
|
}
|
|
|
|
/** @overload
|
|
* @deprecated Use anno_u32() instead. */
|
|
inline uint32_t *Packet::all_user_anno_u() {
|
|
return anno_u32() + user_anno_offset / 4;
|
|
}
|
|
|
|
/** @brief Return user annotation byte @a i.
|
|
* @deprecated Use anno_u8() instead. */
|
|
inline uint8_t Packet::user_anno_c(int i) const {
|
|
return anno_u8(user_anno_offset + i);
|
|
}
|
|
|
|
/** @brief Set user annotation byte @a i.
|
|
* @deprecated Use set_anno_u8() instead. */
|
|
inline void Packet::set_user_anno_c(int i, uint8_t v) {
|
|
set_anno_u8(user_anno_offset + i, v);
|
|
}
|
|
|
|
/** @brief Return 16-bit user annotation @a i.
|
|
* @deprecated Use anno_u16() instead. */
|
|
inline uint16_t Packet::user_anno_us(int i) const {
|
|
return anno_u16(user_anno_offset + i * 2);
|
|
}
|
|
|
|
/** @brief Set 16-bit user annotation @a i.
|
|
* @deprecated Use set_anno_u16() instead. */
|
|
inline void Packet::set_user_anno_us(int i, uint16_t v) {
|
|
set_anno_u16(user_anno_offset + i * 2, v);
|
|
}
|
|
|
|
/** @brief Return 16-bit user annotation @a i.
|
|
* @deprecated Use anno_u16() instead. */
|
|
inline int16_t Packet::user_anno_s(int i) const {
|
|
return (int16_t) anno_u16(user_anno_offset + i * 2);
|
|
}
|
|
|
|
/** @brief Set 16-bit user annotation @a i.
|
|
* @deprecated Use set_anno_u16() instead. */
|
|
inline void Packet::set_user_anno_s(int i, int16_t v) {
|
|
set_anno_u16(user_anno_offset + i * 2, v);
|
|
}
|
|
|
|
/** @brief Return 32-bit user annotation @a i.
|
|
* @deprecated Use anno_u32() instead. */
|
|
inline uint32_t Packet::user_anno_u(int i) const {
|
|
return anno_u32(user_anno_offset + i * 4);
|
|
}
|
|
|
|
/** @brief Set 32-bit user annotation @a i.
|
|
* @deprecated Use set_anno_u32() instead. */
|
|
inline void Packet::set_user_anno_u(int i, uint32_t v) {
|
|
set_anno_u32(user_anno_offset + i * 4, v);
|
|
}
|
|
|
|
/** @brief Return 32-bit user annotation @a i.
|
|
* @deprecated Use anno_s32() instead. */
|
|
inline int32_t Packet::user_anno_i(int i) const {
|
|
return anno_s32(user_anno_offset + i * 4);
|
|
}
|
|
|
|
/** @brief Set 32-bit user annotation @a i.
|
|
* @deprecated Use set_anno_s32() instead. */
|
|
inline void Packet::set_user_anno_i(int i, int32_t v) {
|
|
set_anno_s32(user_anno_offset + i * 4, v);
|
|
}
|
|
/** @endcond never */
|
|
|
|
inline unsigned char *
|
|
WritablePacket::data() const
|
|
{
|
|
return const_cast<unsigned char *>(Packet::data());
|
|
}
|
|
|
|
inline unsigned char *
|
|
WritablePacket::end_data() const
|
|
{
|
|
return const_cast<unsigned char *>(Packet::end_data());
|
|
}
|
|
|
|
inline unsigned char *
|
|
WritablePacket::buffer() const
|
|
{
|
|
return const_cast<unsigned char *>(Packet::buffer());
|
|
}
|
|
|
|
inline unsigned char *
|
|
WritablePacket::end_buffer() const
|
|
{
|
|
return const_cast<unsigned char *>(Packet::end_buffer());
|
|
}
|
|
|
|
inline unsigned char *
|
|
WritablePacket::mac_header() const
|
|
{
|
|
return const_cast<unsigned char *>(Packet::mac_header());
|
|
}
|
|
|
|
inline unsigned char *
|
|
WritablePacket::network_header() const
|
|
{
|
|
return const_cast<unsigned char *>(Packet::network_header());
|
|
}
|
|
|
|
inline unsigned char *
|
|
WritablePacket::transport_header() const
|
|
{
|
|
return const_cast<unsigned char *>(Packet::transport_header());
|
|
}
|
|
|
|
inline click_ether *
|
|
WritablePacket::ether_header() const
|
|
{
|
|
return const_cast<click_ether *>(Packet::ether_header());
|
|
}
|
|
|
|
inline click_ip *
|
|
WritablePacket::ip_header() const
|
|
{
|
|
return const_cast<click_ip *>(Packet::ip_header());
|
|
}
|
|
|
|
inline click_ip6 *
|
|
WritablePacket::ip6_header() const
|
|
{
|
|
return const_cast<click_ip6 *>(Packet::ip6_header());
|
|
}
|
|
|
|
inline click_icmp *
|
|
WritablePacket::icmp_header() const
|
|
{
|
|
return const_cast<click_icmp *>(Packet::icmp_header());
|
|
}
|
|
|
|
inline click_tcp *
|
|
WritablePacket::tcp_header() const
|
|
{
|
|
return const_cast<click_tcp *>(Packet::tcp_header());
|
|
}
|
|
|
|
inline click_udp *
|
|
WritablePacket::udp_header() const
|
|
{
|
|
return const_cast<click_udp *>(Packet::udp_header());
|
|
}
|
|
|
|
/** @cond never */
|
|
inline unsigned char *
|
|
WritablePacket::buffer_data() const
|
|
{
|
|
return const_cast<unsigned char *>(Packet::buffer());
|
|
}
|
|
/** @endcond never */
|
|
|
|
CLICK_ENDDECLS
|
|
#endif
|