/*

Copyright (C) 2000 - 2006 Christian Kreibich <christian@whoop.org>.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be
given in the documentation and software packages that this Software was
used.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/
#ifndef __libnd_protocol_h
#define __libnd_protocol_h

#include <libnd_registry.h>
#include <libnd_packet.h>
#include <libnd_protocol_plugin.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#define LND_PROTO_MAGICS 3


/* A protocol can live at a combination of the following
 * layers.
 */
typedef enum {
  LND_PROTO_LAYER_LINK  = (1 << 0),
  LND_PROTO_LAYER_NET   = (1 << 1),
  LND_PROTO_LAYER_TRANS = (1 << 2),
  LND_PROTO_LAYER_APP   = (1 << 3),
} LND_ProtocolLayer;

struct lnd_protocol
{
  /* Protocol-specific callbacks -- these all get initialized
   * to no-op callbacks, so you can safely call them without
   * checking for existance, but do NOT set the to NULL :)
   */

  /* Initialization routine for this protocol. Use this to
   * hook stuff into the menus etc.
   */
  void         (*init_proto)          (void);

  /* Initialize packet settings according to this
   * protocol and propagate to more nested packets.
   * Automatically called when a protocol is registered
   * with the protocol registry. DATA points to the
   * beginning of the data for this protocol, DATA_END
   * to the first byte following the the last byte.
   *
   * The return value is the first byte after the last
   * one actually used; i.e., if the initialization uses
   * all of the given data, the return value should be
   * equal to DATA_END. Otherwise, it has to be less than
   * DATA_END, but greater than DATA.
   */
  guchar      *(*init_packet)         (LND_Packet *packet,
				       guchar *data,
				       guchar *data_end);

  /* Whether the packet contains the full header of
   * this protocol
   */
  gboolean     (*header_complete)     (const LND_Packet *packet,
				       guint nesting);

  /* Repair a packet in whatever way necessary, for
   * example recalculating checksums etc. Supposed to
   * return TRUE when the packet was modified, FALSE
   * otherwise.
   */
  gboolean     (*fix_packet)          (LND_Packet *packet);

  /* Whether or not it makes sense to repair the parts of a
   * packet beyond the given protocol datapoint. For example,
   * for IPv4 it makes no sense to go beyond the IP header if
   * the payload is an IP fragment.
   */
  gboolean     (*can_fix_proceed)     (LND_Packet *packet,
				       LND_ProtoData *pd);

  /* Adjust header fields as necessary, if the entire packet's
   * size has been adjusted by +/- delta bytes. Should return
   * %TRUE if a modification has been made, %FALSE otherwise.
   */
  gboolean     (*adjust_len)          (LND_Packet *packet, int delta);


  /* State management, for stateful protocols like TCP.
   * The idea is to manage state per trace, as much
   * as appropriate for the protocol.
   */
  void         (*init_state)          (LND_Trace *trace);

  /* Tell the protocol plugin to update its state based
   * on the given packet. Things may be faster when you
   * know a packet's index, so you can pass that as well.
   * If you don't know it, pass a negative value.
   */
  void         (*update_state)        (const LND_Packet *packet, int index);

  /* This is for protocols that want to modify the tcpdump line as
   * it is returned from tcpdump directly.
   */
  void         (*update_tcpdump_line) (const LND_Packet *packet, char *line);

  /* Gets called when a trace is closed, with the trace
   * as parameter.
   */
  void         (*free_state)          (LND_Trace *trace);
  
  /* Each protocol gets a numeric id dynamically assigned when
   * it is created -- a bit value 1,2,4 etc for easy identification
   * of the protocol headers contained in a packet. See
   * LND_Packet->protocols for more.
   *
   * This imposes a limit of 64 supported protocols, but that
   * should suffice for a while ...
   */
  gint64                     id;

  char                      *name;

  /* What layer does this protocol live at? */
  LND_ProtocolLayer          layer;

  /* Up to three magic values that identify this protocol, like 0x0800
   * identifies IP in Ethernet, or port 6 identifies TCP in IP. For some
   * protocols it makes sense to define multiple magics, such as ARP.
   */
  guint32                    magic[LND_PROTO_MAGICS];

  /* Track explicitly how many magic values have been assigned.
   * Since it is possible that 0x00000000 is a valid magic, we
   * cannot rely on magic[i] != 0.
   */
  gboolean                   num_magics;
  
  /* The plugin that created this protocol: */
  LND_ProtoPlugin           *plugin;

  int                        is_stateful : 1;

  /* A registry to associate arbitrary data with a protocol: */
  LND_Registry              *registry;
};


/**
 * libnd_proto_new - creates new protocol.
 * @name: name of the protocol.
 * @layer: layer in the network stack that the new protocol lives at.
 * @magic: the magic value by which the protocol is commonly identified by the layer below.
 *
 * The function creates a new protocol with dummy operations hooked
 * into the function pointers. Commonly used magic values are the
 * DLT_xxx constants from bpf.h for the linklevel, ETHERTYPE_xxx for
 * the network layer, IPPROTO_xxx for the transport layer, and ports
 * as given in /etc/services for the application layer.
 *
 * Returns: new protocol, or %NULL on error.
 */
LND_Protocol      *libnd_proto_new(const char *name,
				   LND_ProtocolLayer layer,
				   guint32 magic);

/**
 * libnd_proto_free - releases memory allocated with a protocol.
 * @proto: protocol to free.
 *
 * The function releases all memory associated with a protocol.
 */
void               libnd_proto_free(LND_Protocol *proto);

/**
 * libnd_proto_add_magic - adds another magic value to a protocol.
 * @proto: protocol to add magic to.
 * @magic: the magic to add.
 *
 * The function adds the additional @magic to the protocol's magic
 * values. The function returns %TRUE if this was successful, or
 * %FALSE if there are too many magic numbers already.
 */
gboolean           libnd_proto_add_magic(LND_Protocol *proto, guint32 magic);

/**
 * libnd_proto_get_num_magics - returns number of magics values for protocol.
 * @proto: protocol to query.
 *
 * Returns: the number of magic values stored for a given protocol.
 */
int                libnd_proto_get_num_magics(LND_Protocol *proto);
  
/**
 * libnd_proto_is_raw - predicate to test whether a protocol is the built-in raw protocol.
 * @proto: protocol to test.
 *
 * Use this function to determine whether a protocol is the
 * built-in raw data protocol.
 *
 * Returns: %TRUE if @proto is the raw protocol, %FALSE otherwise.
 */
gboolean           libnd_proto_is_raw(LND_Protocol *proto);

/**
 * libnd_proto_layer_to_string - returns a string for a protocol layer identifier.
 * @layer: layer identifier.
 *
 * Mainly for debugging purposes, this function returns a statically
 * allocated string for the protocol layer identifier given in @layer.
 */
const char        *libnd_proto_layer_to_string(LND_ProtocolLayer layer);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif
