/*en    Laurent Constantin's network library (lcrzo)
                 lcrzo_header module

  Functions herein allow to create and convert headers.
*/
/*fr    Bibliotheque reseau de Laurent Constantin (lcrzo)
                 Module lcrzo_header

  Les fonctions presentes dans ce module permettent de creer ou
  d'analyser des entetes de paquets.
*/

/*EN***************************************************************
 * Note about logical and physical headers :
 * Network packet contains for example :
 *   ethernet_header ip_header udp_header udp_data
 * Values used in these header are in the "Big Endian" format.
 * So, when we want to work on headers, we have to convert
 * from host to network (htonx) or from network to host (ntohx).
 *
 * To simplify lcrzo use, two types are purposed :
 *  - logical headers : they are in host format
 *  - physical headers : they are in network format
 * 
 * For example, to affect a source port :
 *  - of a logical UDP header, we use :
 *        hdrludp.sport=80;
 *  - of a physical UDP header, we use :
 *        hdrpudp.sport=lcrzo_htons(80);
 *
 * For example, to read a source port : 
 *  - of a logical UDP header, we use :
 *        valeur = hdrludp.sport;
 *  - of a physical UDP header, we use :
 *        valeur = lcrzo_ntohs(hdrpudp.sport);
 *
 * As you may see, logical headers are easier to use.
 * On the other hand, physical headers exactly reflect
 * what's on the wire.
 * 
 * All the functions in lcrzo use logical headers, which allow
 * easy use of headers.
 *
 * Below you can find functions to convert between both types,
 * to suit your needs.
 ****************************************************************/
/*FR***************************************************************
 * Note sur les entetes logiques et physiques :
 * Les paquets issus du reseau sont par exemple de la forme :
 *   entete_ethernet entete_ip entete_udp donnees_udp
 * Les valeurs stockees dans les differents entetes
 * sont au format "Big Endian". Lorsque l'on desire travailler
 * sur des entetes, il faut alors normalement convertir les
 * valeurs de "host to network" (htonx) ou "network to host" (ntohx).
 *
 * Afin de simplifier l'emploi de lcrzo, je propose deux types
 * d'entetes :
 *  - les entetes "logiques" : ce sont les entetes au format machine
 *  - les entetes "physiques" : ce sont les entetes au format reseau
 *
 * Par exemple, pour affecter le port source :
 *  - d'un entete UDP "logique", il faut faire
 *        hdrludp.sport=80;
 *  - d'un entete UDP "physique", il faut faire
 *        hdrpudp.sport=lcrzo_htons(80);
 * 
 * Par exemple, pour lire le port source :
 *  - d'un entete UDP "logique", il faut faire
 *        valeur = hdrludp.sport;
 *  - d'un entete UDP "physique", il faut faire
 *        valeur = lcrzo_ntohs(hdrpudp.sport);
 * 
 * Comme on peut le voir, les entetes logiques sont beaucoup plus
 * simples a utiliser. D'un autre cote, les entetes physiques
 * correspondent exactement a ce qui transite sur le reseau.
 *
 * Toutes les fonctions de lcrzo ont pour interface des entetes
 * logiques, ce qui les rend simples d'emploi.
 *
 * Ci dessous, des entetes physiques sont aussi proposees, si vous
 * desirez pouvoir acceder directement a des paquets reseau, sans
 * utiliser des fonctions de lcrzo.
 ****************************************************************/

/*-------------------------------------------------------------*/
/*en definition of logical headers */
/*fr definition des entetes logiques */

/*en logical header for ethernet header*/
/*fr entete "logique" de paquet ethernet */
typedef struct
{ lcrzo_etha   dst;
  lcrzo_etha   src;
  lcrzo_uint16 type;
} lcrzo_hdrleth;

/*en logical header for IP header*/
/*fr entete "logique" de paquet IP */
typedef struct 
{ lcrzo_uint8  version;
  lcrzo_uint8  ihl;
  lcrzo_uint8  tos;
  lcrzo_uint16 totlen;
  lcrzo_uint16 id;
  lcrzo_bool   reserve;
  lcrzo_bool   dontfrag;
  lcrzo_bool   morefrag;
  lcrzo_uint16 offsetfrag;
  lcrzo_uint8  ttl;
  lcrzo_uint8  protocol;
  lcrzo_uint16 check;
  lcrzo_uint32 saddr;
  lcrzo_uint32 daddr;
} lcrzo_hdrlip;

/*en logical header for UDP header*/
/*fr entete "logique" de paquet UDP */
typedef struct
{ lcrzo_uint16 sport;
  lcrzo_uint16 dport;
  lcrzo_uint16 len;
  lcrzo_uint16 check;
} lcrzo_hdrludp;

/*en logical header for TCP header*/
/*fr entete "logique" de paquet TCP */
typedef struct
{
  lcrzo_uint16 sport;
  lcrzo_uint16 dport;
  lcrzo_uint32 seqnum;
  lcrzo_uint32 acknum;
  lcrzo_uint8  doff;
  lcrzo_uint8  reserve;
  lcrzo_bool   urg;
  lcrzo_bool   ack;
  lcrzo_bool   psh;
  lcrzo_bool   rst;
  lcrzo_bool   syn;
  lcrzo_bool   fin;
  lcrzo_uint16 window;
  lcrzo_uint16 check;
  lcrzo_uint16 urgptr;
} lcrzo_hdrltcp;

/*en logical header for ICMP header*/
/*fr entete "logique" de paquet ICMP */
typedef struct
{ lcrzo_uint8  type;
  lcrzo_uint8  code;
  lcrzo_uint16 check;
} lcrzo_hdrlicmp;

/*en logical header for ARP/RARP header (specific for ethernet<-->ip)) */
/*fr entete "logique" de paquet arp/rarp (specifique a ethernet<-->ip) */
typedef struct
{ lcrzo_uint16 hw_type;    /*1:ethernet 10/100Mbps*/
  lcrzo_uint16 prot_type;  /*0x0800:ip*/
  lcrzo_uint8  hw_size;    /*6*/
  lcrzo_uint8  prot_size;  /*4*/
  lcrzo_uint16 op;         /*1:arpreq,2:arpreply, 3:rarpreq,4:rarpreply*/
  lcrzo_etha   hw_src;
  lcrzo_ipa    prot_src;
  lcrzo_etha   hw_dst;
  lcrzo_ipa    prot_dst;
} lcrzo_hdrlarp;

/*-------------------------------------------------------------*/
/*en definition of physical headers */
/*fr definition des entetes physiques */

/*en physical header for ethernet header*/
/*fr entete physique de paquet ethernet */
typedef struct
{ lcrzo_etha   dst;
  lcrzo_etha   src;
  lcrzo_uint16 type;
} lcrzo_hdrpeth;

/*en physical header for IP header*/
/*fr entete physique de paquet IP */
#if LCRZODEF_ENDIANLITTLE==1
typedef struct 
{ unsigned int ihl:4; 
  unsigned int version:4;
  unsigned int tos:8;
  unsigned int totlen:16;
  lcrzo_uint16 id;
  lcrzo_uint16 fragoff;
  lcrzo_uint8  ttl;
  lcrzo_uint8  protocol;
  lcrzo_uint16 check;
  lcrzo_uint32 saddr;
  lcrzo_uint32 daddr;
} lcrzo_hdrpip;
#elif LCRZODEF_ENDIANBIG==1
typedef struct 
{ unsigned int version:4;
  unsigned int ihl:4;
  unsigned int tos:8;
  unsigned int totlen:16;
  lcrzo_uint16 id;
  lcrzo_uint16 fragoff;
  lcrzo_uint8  ttl;
  lcrzo_uint8  protocol;
  lcrzo_uint16 check;
  lcrzo_uint32 saddr;
  lcrzo_uint32 daddr;
} lcrzo_hdrpip;
#endif
/*en these defines permit to access to fragment bits */
/*fr les defines suivants permettent d'acceder aux bits de fragment*/
/*enreserved*/
/*frreserve*/
#define LCRZO_HDRPIP_RF_NH(i)  ((lcrzo_int8)((lcrzo_ntohs(i)&0x8000)>>15))
#define LCRZO_HDRPIP_RF_HN(i)  (lcrzo_htons( (1&(i))<<15 ))
/*dontfrag*/
#define LCRZO_HDRPIP_DF_NH(i)  ((lcrzo_int8)((lcrzo_ntohs(i)&0x4000)>>14))
#define LCRZO_HDRPIP_DF_HN(i)  (lcrzo_htons( (1&(i))<<14 ))
/*morefrag*/
#define LCRZO_HDRPIP_MF_NH(i)  ((lcrzo_int8)((lcrzo_ntohs(i)&0x2000)>>13))
#define LCRZO_HDRPIP_MF_HN(i)  (lcrzo_htons( (1&(i))<<13 ))
/*offset*/
#define LCRZO_HDRPIP_OFF_NH(i) ((lcrzo_uint16)(lcrzo_ntohs(i)&0x1FFF))
#define LCRZO_HDRPIP_OFF_HN(i) (lcrzo_htons( 0x1FFF&(i)  ))

/*en physical header for UDP header*/
/*fr entete physique de paquet UDP */
typedef struct
{ lcrzo_uint16 sport;
  lcrzo_uint16 dport;
  lcrzo_uint16 len;
  lcrzo_uint16 check;
} lcrzo_hdrpudp;

/*en physical header for TCP header*/
/*fr entete physique de paquet TCP */
#if LCRZODEF_ENDIANLITTLE==1
typedef struct
{
  lcrzo_uint16 sport;
  lcrzo_uint16 dport;
  lcrzo_uint32 seqnum;
  lcrzo_uint32 acknum;
  unsigned int res1:4;
  unsigned int doff:4;
  unsigned int fin:1;
  unsigned int syn:1;
  unsigned int rst:1;
  unsigned int psh:1;
  unsigned int ack:1;
  unsigned int urg:1;
  unsigned int res2:2;
  unsigned int window:16;
  lcrzo_uint16 check;
  lcrzo_uint16 urgptr;
} lcrzo_hdrptcp;
#elif LCRZODEF_ENDIANBIG==1
typedef struct
{
  lcrzo_uint16 sport;
  lcrzo_uint16 dport;
  lcrzo_uint32 seqnum;
  lcrzo_uint32 acknum;
  unsigned int doff:4;
  unsigned int res1:4;
  unsigned int res2:2;
  unsigned int urg:1;
  unsigned int ack:1;
  unsigned int psh:1;
  unsigned int rst:1;
  unsigned int syn:1;
  unsigned int fin:1;
  unsigned int window:16;
  lcrzo_uint16 check;
  lcrzo_uint16 urgptr;
} lcrzo_hdrptcp;
#endif

/*en physical header for ICMP header*/
/*fr entete physique de paquet ICMP */
typedef struct
{ lcrzo_uint8  type;
  lcrzo_uint8  code;
  lcrzo_uint16 check;
} lcrzo_hdrpicmp;

/*en physical header for ARP/RARP header*/
/*fr entete physique de paquet ARP/RARP */
typedef struct
{ lcrzo_uint16 hw_type;    /*1:ethernet 10/100Mbps*/
  lcrzo_uint16 prot_type;  /*0x0800:ip*/
  lcrzo_uint8  hw_size;    /*6*/
  lcrzo_uint8  prot_size;  /*4*/
  lcrzo_uint16 op;         /*1:arpreq,2:arpreply, 3:rarpreq,4:rarpreply*/
  lcrzo_etha   hw_src;
  lcrzo_ipa    prot_src;
  lcrzo_etha   hw_dst;
  lcrzo_ipa    prot_dst;
} lcrzo_hdrparp;

/*-------------------------------------------------------------*/
/* Ethernet types */
/* types Ethernet */
#define LCRZO_HDRLETH_TYPE_IP   0x0800
#define LCRZO_HDRLETH_TYPE_ARP  0x0806
#define LCRZO_HDRLETH_TYPE_RARP 0x8035

/*-------------------------------------------------------------*/
/* IP protocols */
/* protocoles IP */
#define LCRZO_HDRLIP_PROTOCOL_ICMP  1
#define LCRZO_HDRLIP_PROTOCOL_TCP   6
#define LCRZO_HDRLIP_PROTOCOL_UDP  17

/*-------------------------------------------------------------*/
/*en initialize an Ethernet logical header */
/*fr initialise un entete logique Ethernet */
#define LCRZO_HDRLETH_TYPE_DEFVAL     0
int lcrzo_hdrleth_initdefault(lcrzo_hdrleth *phdrleth);

/*en initialize an IP logical header */
/*fr initialise un entete logique IP */
#define LCRZO_HDRLIP_TOTLEN_DEFVAL   20
#define LCRZO_HDRLIP_IHL_DEFVAL       5
#define LCRZO_HDRLIP_CHECK_DEFVAL     0
#define LCRZO_HDRLIP_PROTOCOL_DEFVAL  0
int lcrzo_hdrlip_initdefault(lcrzo_hdrlip *phdrlip);

/*en initialize an UDP logical header */
/*fr initialise un entete logique UDP */
#define LCRZO_HDRLUDP_LEN_DEFVAL      8
#define LCRZO_HDRLUDP_CHECK_DEFVAL    0 
int lcrzo_hdrludp_initdefault(lcrzo_hdrludp *phdrludp);

/*en initialize a TCP logical header */
/*fr initialise un entete logique TCP */
#define LCRZO_HDRLTCP_DOFF_DEFVAL     5
#define LCRZO_HDRLTCP_CHECK_DEFVAL    0
int lcrzo_hdrltcp_initdefault(lcrzo_hdrltcp *phdrltcp);

/*en initialize an ICMP logical header */
/*fr initialise un entete logique ICMP */
#define LCRZO_HDRLICMP_CHECK_DEFVAL   0
int lcrzo_hdrlicmp_initdefault(lcrzo_hdrlicmp *phdrlicmp);

/*en initialize an ARP/RARP logical header */
/*fr initialise un entete logique ARP/RARP */
int lcrzo_hdrlarp_initdefault(lcrzo_hdrlarp *phdrlarp);

/*-------------------------------------------------------------*/
/*en convert from logical header to physical header */
/*fr conversion d'entete logique a physique */
int lcrzo_hdrpeth_init_hdrleth(lcrzo_hdrleth hdrleth,
			       lcrzo_hdrpeth *phdrpeth);
int lcrzo_hdrpip_init_hdrlip(lcrzo_hdrlip hdrlip,
			     lcrzo_hdrpip *phdrpip);
int lcrzo_hdrpudp_init_hdrludp(lcrzo_hdrludp hdrludp,
			       lcrzo_hdrpudp *phdrpudp);
int lcrzo_hdrptcp_init_hdrltcp(lcrzo_hdrltcp hdrltcp,
			       lcrzo_hdrptcp *phdrptcp);
int lcrzo_hdrpicmp_init_hdrlicmp(lcrzo_hdrlicmp hdrlicmp,
				 lcrzo_hdrpicmp *phdrpicmp);
int lcrzo_hdrparp_init_hdrlarp(lcrzo_hdrlarp hdrlarp,
			       lcrzo_hdrparp *phdrparp);

/*-------------------------------------------------------------*/
/*en convert from physical header to logical header */
/*fr conversion d'entete physique a logique */
int lcrzo_hdrleth_init_hdrpeth(lcrzo_hdrpeth hdrpeth,
			       lcrzo_hdrleth *phdrleth);
int lcrzo_hdrlip_init_hdrpip(lcrzo_hdrpip hdrpip,
			     lcrzo_hdrlip *phdrlip);
int lcrzo_hdrludp_init_hdrpudp(lcrzo_hdrpudp hdrpudp,
			       lcrzo_hdrludp *phdrludp);
int lcrzo_hdrltcp_init_hdrptcp(lcrzo_hdrptcp hdrptcp,
			       lcrzo_hdrltcp *phdrltcp);
int lcrzo_hdrlicmp_init_hdrpicmp(lcrzo_hdrpicmp hdrpicmp,
				 lcrzo_hdrlicmp *phdrlicmp);
int lcrzo_hdrlarp_init_hdrparp(lcrzo_hdrparp hdrparp,
			       lcrzo_hdrlarp *phdrlarp);

/*-------------------------------------------------------------*/
/*en update fields of phdrxxx, with modified fields from fieldstomodify */
/*fr met a jour les champs de phdrxxx, avec les champs modifies
     de fieldstomodify */
int lcrzo_hdrleth_update(lcrzo_hdrleth fieldstomodify,
			 lcrzo_hdrleth *phdreth);
int lcrzo_hdrlip_update(lcrzo_hdrlip fieldstomodify,
			lcrzo_hdrlip *phdrip);
int lcrzo_hdrludp_update(lcrzo_hdrludp fieldstomodify,
			 lcrzo_hdrludp *phdrudp);
int lcrzo_hdrltcp_update(lcrzo_hdrltcp fieldstomodify,
			 lcrzo_hdrltcp *phdrtcp);
int lcrzo_hdrlicmp_update(lcrzo_hdrlicmp fieldstomodify,
			  lcrzo_hdrlicmp *phdricmp);
int lcrzo_hdrlarp_update(lcrzo_hdrlarp fieldstomodify,
			 lcrzo_hdrlarp *phdrarp);
