// -*- c-basic-offset: 4 -*- #ifndef CLICK_IPREASSEMBLER_HH #define CLICK_IPREASSEMBLER_HH #include #include #include #include CLICK_DECLS /* =c IPReassembler([I]) =s ip Reassembles fragmented IP packets =d Expects IP packets as input to port 0. If input packets are fragments, IPReassembler holds them until it has enough fragments to recreate a complete packet. When a complete packet is constructed, it is emitted onto output 0. If a set of fragments making a single packet is incomplete and dormant for 30 seconds, the fragments are generally dropped. If IPReassembler has two outputs, however, a single packet containing all the received fragments at their proper offsets is pushed onto output 1. IPReassembler's memory usage is bounded. When memory consumption rises above HIMEM bytes, IPReassembler throws away old fragments until memory consumption drops below 3/4*HIMEM bytes. Default HIMEM is 256K. Keyword arguments are: =over 8 =item HIMEM The upper bound for memory consumption, in bytes. Default is 256K. =back =n You may want to attach an C to the second output. IPReassembler destroys its input packets' "next packet" annotations. =a IPFragmenter */ class IPReassembler : public Element { public: IPReassembler(); ~IPReassembler(); const char *class_name() const { return "IPReassembler"; } const char *port_count() const { return "1/1-2"; } const char *processing() const { return "a/ah"; } int configure(Vector &, ErrorHandler *); int initialize(ErrorHandler *); void cleanup(CleanupStage); int check(ErrorHandler * = 0); Packet *simple_action(Packet *); struct ChunkLink { uint16_t off; uint16_t lastoff; }; struct PacketInfo { uint32_t padding[3]; // preserve paint annotation ChunkLink chunk; }; private: enum { REAP_TIMEOUT = 30, // seconds REAP_INTERVAL = 10, // seconds IPH_MEM_USED = 40 }; enum { NMAP = 256 }; WritablePacket *_map[NMAP]; int _reap_time; uint32_t _mem_used; uint32_t _mem_high_thresh; // defaults to 256K uint32_t _mem_low_thresh; // defaults to 3/4 * _mem_high_thresh static inline int bucketno(const click_ip *); static inline bool same_segment(const click_ip *, const click_ip *); WritablePacket *find_queue(Packet *, WritablePacket ***); void make_queue(Packet *, WritablePacket **); static ChunkLink *next_chunk(WritablePacket *, ChunkLink *); Packet *emit_whole_packet(WritablePacket *, WritablePacket **, Packet *); void reap_overfull(int); void reap(int); static void check_error(ErrorHandler *, int, const Packet *, const char *, ...); }; inline int IPReassembler::bucketno(const click_ip *h) { return (h->ip_id % NMAP); } inline bool IPReassembler::same_segment(const click_ip *h, const click_ip *h2) { return h->ip_id == h2->ip_id && h->ip_p == h2->ip_p && h->ip_src.s_addr == h2->ip_src.s_addr && h->ip_dst.s_addr == h2->ip_dst.s_addr; } CLICK_ENDDECLS #endif