/*
 *  OpenVPN -- An application to securely tunnel IP networks
 *             over a single UDP port, with support for SSL/TLS-based
 *             session authentication and key exchange,
 *             packet encryption, packet authentication, and
 *             packet compression.
 *
 *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program (see the file COPYING included with this
 *  distribution); if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef FRAGMENT_H
#define FRAGMENT_H

/**
 * @file
 * Data Channel Fragmentation module header file.
 */


#ifdef ENABLE_FRAGMENT

/**
 * @addtogroup fragmentation
 * @{
 */


#include "common.h"
#include "buffer.h"
#include "interval.h"
#include "mtu.h"
#include "shaper.h"
#include "error.h"


#define N_FRAG_BUF                   25
                                /**< Number of packet buffers for
                                 *   reassembling incoming fragmented
                                 *   packets. */

#define FRAG_TTL_SEC                 10
                                /**< Time-to-live in seconds for a %fragment. */

#define FRAG_WAKEUP_INTERVAL         5
                                /**< Interval in seconds between calls to
                                 *   wakeup code. */

/**************************************************************************/
/**
 * Structure for reassembling one incoming fragmented packet.
 */
struct fragment {
  bool defined;                 /**< Whether reassembly is currently
                                 *   taking place in this structure. */

  int max_frag_size;		/**< Maximum size of each %fragment. */

# define FRAG_MAP_MASK 0xFFFFFFFF
                                /**< Mask for reassembly map. */
# define MAX_FRAGS 32		/**< Maximum number of fragments per packet. */
  unsigned int map;
                                /**< Reassembly map for recording which
                                 *   fragments have been received.
                                 *
                                 *   A bit array where each bit
                                 *   corresponds to a %fragment.  A 1 bit
                                 *   in element n means that the %fragment
                                 *   n has been received.  Needs to have
                                 *   at least \c MAX_FRAGS bits. */

  time_t timestamp;		/**< Timestamp for time-to-live purposes. */

  struct buffer buf;            /**< Buffer in which received datagrams
                                 *   are reassembled. */
};


/**
 * List of fragment structures for reassembling multiple incoming packets
 * concurrently.
 */
struct fragment_list {
  int seq_id;                   /**< Highest fragmentation sequence ID of
                                 *   the packets currently being
                                 *   reassembled. */
  int index;                    /**< Index of the packet being reassembled
                                 *   with the highest fragmentation
                                 *   sequence ID into the \c
                                 *   fragment_list.fragments array. */

/** Array of reassembly structures, each can contain one whole packet.
 *
 *  The fragmentation sequence IDs of the packets being reassembled in
 *  this array are linearly increasing. \c
 *  fragment_list.fragments[fragment_list.index] has an ID of \c
 *  fragment_list.seq_id.  This means that one of these \c fragment_list
 *  structures can at any one time contain at most packets with the
 *  fragmentation sequence IDs in the range \c fragment_list.seq_id \c -
 *  \c N_FRAG_BUF \c + \c 1 to \c fragment_list.seq_id, inclusive.
 */
  struct fragment fragments[N_FRAG_BUF];
};


/**
 * Fragmentation and reassembly state for one VPN tunnel instance.
 *
 * This structure contains all the state necessary for sending and
 * receiving fragmented data channel packets associated with one VPN
 * tunnel.
 *
 * The fragmented packet currently being sent to a remote OpenVPN peer is
 * stored in \c fragment_master.outgoing.  It is copied into that buffer
 * by the \c fragment_outgoing() function and the remaining parts to be
 * sent can be retrieved by successive calls to \c
 * fragment_ready_to_send().
 *
 * The received packets currently being reassembled are stored in the \c
 * fragment_master.incoming array of \c fragment structures.  The \c
 * fragment_incoming() function adds newly received parts into this array
 * and returns the whole packets once reassembly is complete.
 */
struct fragment_master {
  struct event_timeout wakeup;  /**< Timeout structure used by the main
                                 *   event loop to know when to do
                                 *   fragmentation housekeeping. */
  bool received_os_mtu_hint;    /**< Whether the operating system has
                                 *   explicitly recommended an MTU value. */
# define N_SEQ_ID            256
                                /**< One more than the maximum fragment
                                 *   sequence ID, above which the IDs wrap
                                 *   to zero.  Should be a power of 2. */
  int outgoing_seq_id;          /**< Fragment sequence ID of the current
                                 *   fragmented packet waiting to be sent.
                                 *
                                 *   All parts of a fragmented packet
                                 *   share the same sequence ID, so that
                                 *   the remote OpenVPN peer can determine
                                 *   which parts belong to which original
                                 *   packet. */
# define MAX_FRAG_PKT_SIZE 65536
                                /**< (Not used) Maximum packet size before
                                 *   fragmenting. */
  int outgoing_frag_size;       /**< Size in bytes of each part to be
                                 *   sent, except for the last part which
                                 *   may be smaller.
                                 *
                                 *   This value is computed by the \c
                                 *   optimal_fragment_size() function. Its
                                 *   value is sent to the remote peer in
                                 *   the fragmentation header of the last
                                 *   part (i.e. with %fragment type \c
                                 *   FRAG_YES_LAST) using the \c
                                 *   FRAG_SIZE_MASK and \c FRAG_SIZE_SHIFT
                                 *   bits. */
  int outgoing_frag_id;         /**< The fragment ID of the next part to
                                 *   be sent.  Must have a value between 0
                                 *   and \c MAX_FRAGS-1. */
  struct buffer outgoing;       /**< Buffer containing the remaining parts
                                 *   of the fragmented packet being sent. */
  struct buffer outgoing_return;
                                /**< Buffer used by \c
                                 *   fragment_ready_to_send() to return a
                                 *   part to send. */

  struct fragment_list incoming;
                                /**< List of structures for reassembling
                                 *   incoming packets. */
};


/**************************************************************************/
/** @name Fragment header
 *  @todo Add description of %fragment header format.
 *//** @{ *//*************************************/

typedef uint32_t fragment_header_type;
                                /**< Fragmentation information is stored in
                                 *   a 32-bit packet header. */

#define hton_fragment_header_type(x) htonl(x)
                                /**< Convert a fragment_header_type from
                                 *   host to network order. */

#define ntoh_fragment_header_type(x) ntohl(x)
                                /**< Convert a \c fragment_header_type
                                 *   from network to host order. */

#define FRAG_TYPE_MASK        0x00000003
                                /**< Bit mask for %fragment type info. */
#define FRAG_TYPE_SHIFT       0 /**< Bit shift for %fragment type info. */

#define FRAG_WHOLE            0 /**< Fragment type indicating packet is
                                 *   whole. */
#define FRAG_YES_NOTLAST      1 /**< Fragment type indicating packet is
                                 *   part of a fragmented packet, but not
                                 *   the last part in the sequence. */
#define FRAG_YES_LAST         2 /**< Fragment type indicating packet is
                                 *   the last part in the sequence of
                                 *   parts. */
#define FRAG_TEST             3 /**< Fragment type not implemented yet.
                                 *   In the future might be used as a
                                 *   control packet for establishing MTU
                                 *   size. */

#define FRAG_SEQ_ID_MASK      0x000000ff
                                /**< Bit mask for %fragment sequence ID. */
#define FRAG_SEQ_ID_SHIFT     2 /**< Bit shift for %fragment sequence ID. */

#define FRAG_ID_MASK          0x0000001f
                                /**< Bit mask for %fragment ID. */
#define FRAG_ID_SHIFT         10
                                /**< Bit shift for %fragment ID. */

/*
 * FRAG_SIZE  14 bits
 *
 * IF FRAG_YES_LAST (FRAG_SIZE):
 *   The max size of a %fragment.  If a %fragment is not the last %fragment in the packet,
 *   then the %fragment size is guaranteed to be equal to the max %fragment size.  Therefore,
 *   max_frag_size is only sent over the wire if FRAG_LAST is set.  Otherwise it is assumed
 *   to be the actual %fragment size received.
 */
#define FRAG_SIZE_MASK        0x00003fff
                                /**< Bit mask for %fragment size. */
#define FRAG_SIZE_SHIFT       15
                                /**< Bit shift for %fragment size. */
#define FRAG_SIZE_ROUND_SHIFT 2 /**< Bit shift for %fragment size rounding. */
#define FRAG_SIZE_ROUND_MASK ((1 << FRAG_SIZE_ROUND_SHIFT) - 1)
                                /**< Bit mask for %fragment size rounding. */

/*
 * FRAG_EXTRA 16 bits
 *
 * IF FRAG_WHOLE or FRAG_YES_NOTLAST, these 16 bits are available (not currently used)
 */
#define FRAG_EXTRA_MASK         0x0000ffff
                                /**< Bit mask for extra bits. */
#define FRAG_EXTRA_SHIFT        15
                                /**< Bit shift for extra bits. */

/** @} name Fragment header *//********************************************/


/**************************************************************************/
/** @name Functions for initialization and cleanup *//** @{ *//************/

/**
 * Allocate and initialize a \c fragment_master structure.
 *
 * This function also modifies the \a frame packet geometry parameters to
 * include space for the fragmentation header.
 *
 * @param frame        - The packet geometry parameters for this VPN
 *                       tunnel, modified by this function to include the
 *                       fragmentation header.
 *
 * @return A pointer to the new \c fragment_master structure.
 */
struct fragment_master *fragment_init (struct frame *frame);


/**
 * Allocate internal packet buffers for a \c fragment_master structure.
 *
 * @param f            - The \c fragment_master structure for which to
 *                       allocate the internal buffers.
 * @param frame        - The packet geometry parameters for this VPN
 *                       tunnel, used to determine how much memory to
 *                       allocate for each packet buffer.
 */
void fragment_frame_init (struct fragment_master *f, const struct frame *frame);


/**
 * Free a \c fragment_master structure and its internal packet buffers.
 *
 * @param f            - The \c fragment_master structure to free.
 */
void fragment_free (struct fragment_master *f);

/** @} name Functions for initialization and cleanup *//*******************/


/**************************************************************************/
/** @name Functions for processing packets received from a remote OpenVPN peer */
/** @{ */

/**
 * Process an incoming packet, which may or may not be fragmented.
 *
 * This function inspects the fragmentation header of the incoming packet
 * and processes the packet accordingly. Depending on the %fragment type
 * bits (\c FRAG_TYPE_MASK and \c FRAG_TYPE_SHIFT) the packet is processed
 * in the following ways:
 *  - \c FRAG_WHOLE: the packet is not fragmented, and this function does
 *    not modify its contents, except for removing the fragmentation
 *    header.
 *  - \c FRAG_YES_NOTLAST or \c FRAG_YES_LAST: the packet is part of a
 *    fragmented packet.  This function copies the packet into an internal
 *    reassembly buffer.  If the incoming part completes the packet being
 *    reassembled, the \a buf argument is modified to point to the fully
 *    reassembled packet.  If, on the other hand, reassembly is not yet
 *    complete, then the the \a buf buffer is set to empty.
 *  - Any other value: error.
 *
 * If an error occurs during processing, an error message is logged and
 * the length of \a buf is set to zero.
 *
 * @param f            - The \c fragment_master structure for this VPN
 *                       tunnel.
 * @param buf          - A pointer to the buffer structure containing the
 *                       incoming packet.  This pointer will have been
 *                       modified on return either to point to a
 *                       completely reassembled packet, or to have length
 *                       set to zero if reassembly is not yet complete.
 * @param frame        - The packet geometry parameters for this VPN
 *                       tunnel.
 *
 * @return Void.\n On return, the \a buf argument will point to a buffer.
 *     The buffer will have nonzero length if the incoming packet passed
 *     to this function was whole and unfragmented, or if it was the final
 *     part of a fragmented packet thereby completing reassembly.  On the
 *     other hand, the buffer will have a length of zero if the incoming
 *     packet was part of a fragmented packet and reassembly is not yet
 *     complete.  If an error occurs during processing, the buffer length
 *     is also set to zero.
 */
void fragment_incoming (struct fragment_master *f, struct buffer *buf,
			const struct frame* frame);

/** @} name Functions for processing packets received from a VPN tunnel */


/**************************************************************************/
/** @name Functions for processing packets to be sent to a remote OpenVPN peer */
/** @{ */

/**
 * Process an outgoing packet, which may or may not need to be fragmented.
 *
 * This function inspects the outgoing packet, determines whether it needs
 * to be fragmented, and processes it accordingly.
 *
 * Depending on the size of the outgoing packet and the packet geometry
 * parameters for the VPN tunnel, the packet will or will not be
 * fragmented.
 * @li Packet size is less than or equal to the maximum packet size for
 *     this VPN tunnel: fragmentation is not necessary.  The \a buf
 *     argument points to a buffer containing the unmodified outgoing
 *     packet with a fragmentation header indicating the packet is whole
 *     (FRAG_WHOLE) prepended.
 * @li Packet size is greater than the maximum packet size for this VPN
 *     tunnel: fragmentation is necessary.  The original outgoing packet
 *     is copied into an internal buffer for fragmentation.  The \a buf
 *     argument is modified to point to the first part of the fragmented
 *     packet. The remaining parts remain stored in the internal buffer,
 *     and can be retrieved using the \c fragment_ready_to_send()
 *     function.
 *
 * If an error occurs during processing, an error message is logged and
 * the length of \a buf is set to zero.
 *
 * @param f            - The \c fragment_master structure for this VPN
 *                       tunnel.
 * @param buf          - A pointer to the buffer structure containing the
 *                       outgoing packet.  This pointer will be modified
 *                       to point to a whole unfragmented packet or to the
 *                       first part of a fragmented packet on return.
 * @param frame        - The packet geometry parameters for this VPN
 *                       tunnel.
 *
 * @return Void.\n On return, the \a buf argument will point to a buffer.
 *     This buffer contains either the whole original outgoing packet if
 *     fragmentation was not necessary, or the first part of the
 *     fragmented outgoing packet if fragmentation was necessary. In both
 *     cases a fragmentation header will have been prepended to inform the
 *     remote peer how to handle the packet.
 */
void fragment_outgoing (struct fragment_master *f, struct buffer *buf,
			const struct frame* frame);

/**
 * Check whether outgoing fragments are ready to be send, and if so make
 * one available.
 *
 * This function checks whether the internal buffer for fragmenting
 * outgoing packets contains any unsent parts.  If it does not, meaning
 * there is nothing waiting to be sent, it returns false.  Otherwise there
 * are parts ready to be sent, and it returns true.  In that case it also
 * modifies the \a buf argument to point to a buffer containing the next
 * part to be sent.
 *
 * @param f            - The \a fragment_master structure for this VPN
 *                       tunnel.
 * @param buf          - A pointer to a buffer structure which on return,
 *                       if there are parts waiting to be sent, will point
 *                       to the next part to be sent.
 * @param frame        - The packet geometry parameters for this VPN
 *                       tunnel.
 *
 * @return
 * @li True, if an outgoing packet has been fragmented and not all parts
 *     have been sent yet.  In this case this function will modify the \a
 *     buf argument to point to a buffer containing the next part to be
 *     sent.
 * @li False, if there are no outgoing fragmented parts waiting to be
 *     sent.
 */
bool fragment_ready_to_send (struct fragment_master *f, struct buffer *buf,
			     const struct frame* frame);

/**
 * Check whether a \c fragment_master structure contains fragments ready
 * to be sent.
 *
 * @param f            - The \c fragment_master structure for this VPN
 *                       tunnel.
 *
 * @return
 * @li True, if there are one or more fragments ready to be sent.
 * @li False, otherwise.
 */
static inline bool
fragment_outgoing_defined (struct fragment_master *f)
{
  return f->outgoing.len > 0;
}

/** @} name Functions for processing packets going out through a VPN tunnel */


void fragment_wakeup (struct fragment_master *f, struct frame *frame);


/**************************************************************************/
/** @name Functions for regular housekeeping *//** @{ *//******************/

/**
 * Perform housekeeping of a \c fragment_master structure.
 *
 * Housekeeping includes scanning incoming packet reassembly buffers for
 * packets which have not yet been reassembled completely but are already
 * older than their time-to-live.
 *
 * @param f            - The \c fragment_master structure for this VPN
 *                       tunnel.
 * @param frame        - The packet geometry parameters for this VPN
 *                       tunnel.
 */
static inline void
fragment_housekeeping (struct fragment_master *f, struct frame *frame, struct timeval *tv)
{
  if (event_timeout_trigger (&f->wakeup, tv, ETT_DEFAULT))
    fragment_wakeup (f, frame);
}

/** @} name Functions for regular housekeeping *//*************************/


/** @} addtogroup fragmentation *//****************************************/


#endif
#endif
