/*
		                  LCRZO
                             Network library
             Copyright(c) 1999,2000,2001,2002 Laurent Constantin
                                  -----

  Main server    : http://www.laurentconstantin.com/
  Backup servers : http://go.to/laurentconstantin/
                   http://laurentconstantin.est-la.com/
                   http://laurentconstantin.free.fr/
                   http://lauconstantin.multimania.com/
  [my current email address is on the web servers]

                                  -----
  This file is part of Lcrzo.

  Lcrzo is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Lcrzo 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
  Lesser General Public License for more details (http://www.gnu.org).

------------------------------------------------------------------------
*/

/* -- Note about comments and variable names --
   In versions 1.00 up to 2.08, lcrzo was only written in French (my
   mother tongue). Since version 3.00, lcrzo is written in English, but
   most of comments and variable names are still in French.
   In future versions, I'll try to translate everything into English,
   but as you may guess, that's a quite big work...
   So, for the moment, here are some word translation, if you want to
   be able to understand what's going on in the functions :
     afficher - print     ;  ajouter - add         ;  copie - copy
     dernier - last       ;  donnee - data         ;  ecrire - write
     entete - header      ;  envoye - sent         ;  ferme - close
     fichier - file       ;  lire - read           ;  masque - mask 
     nboct - byte number  ;  ouvre, ouvrir - open  ;  paq, paquet - packet
     plage - range        ;  premier - first       ;  recu - received
     reseau - network     ;  retour - return       ;  taille - size
     tunnel - pipe

*/

#include "lcrzo_incl.h"

/*-------------------------------------------------------------*/
/* pseudo header utilise pour le calcul des checksums */
typedef struct 
{ lcrzo_uint32 saddr;
  lcrzo_uint32 daddr;
  lcrzo_uint8  zeros;
  lcrzo_uint8  protocol;
  lcrzo_uint16 len;
} lcrzo_hdrpseudo;

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ipoptdata(lcrzo_hdrlip hdrlip,
				 const lcrzo_ipopt ipopt,
				 lcrzo_uint8 nboctipopt,
				 lcrzo_constdata data, 
				 lcrzo_uint16 nboctdata,
				 lcrzo_data *pdataout,
				 lcrzo_int32 *pdataoutsize)
{ lcrzo_hdrpip hdrpip;
  lcrzo_bool hdr_compfields, hdr_compfield_iptotlen, hdr_compfield_ipihl, hdr_compfield_ipcheck;

  /*parameters verification*/
  if (ipopt==NULL && nboctipopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);
  lcrzo_ipopt_verifbof(nboctipopt);
  /*verifie que la taille des options soit un multiple de 4*/
  if (nboctipopt%4)
    return(LCRZO_ERR_SPOPTNOTX4);
  if ( sizeof(lcrzo_hdrpip)+nboctipopt+nboctdata > 0xFFFF )
    return(LCRZO_ERR_PATOOBIG);

  /*met eventuellement a jour totlen*/
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_iptotlen(&hdr_compfield_iptotlen));
  if (hdrlip.totlen==LCRZO_HDRLIP_TOTLEN_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_iptotlen )
  { hdrlip.totlen = (lcrzo_uint16)(sizeof(lcrzo_hdrpip)+nboctipopt+nboctdata);
  }

  /*met eventuellement a jour ihl*/
  lcrzo_er(lcrzo_global_get_hdr_cf_ipihl(&hdr_compfield_ipihl));
  if (hdrlip.ihl==LCRZO_HDRLIP_IHL_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_ipihl)
  { hdrlip.ihl=(lcrzo_uint8)( (sizeof(lcrzo_hdrpip)+nboctipopt)/4 );
  }

  /*conversion de l'entete logique en entete physique*/
  lcrzo_er(lcrzo_hdrpip_init_hdrlip(hdrlip, &hdrpip));

  /*met eventuellement a jour check*/
  lcrzo_er(lcrzo_global_get_hdr_cf_ipcheck(&hdr_compfield_ipcheck));
  if (hdrpip.check==lcrzo_htons(LCRZO_HDRLIP_CHECK_DEFVAL) &&
      hdr_compfields &&
      hdr_compfield_ipcheck )
  { lcrzo_uint8 buf[sizeof(lcrzo_hdrpip)+sizeof(lcrzo_ipopt)];
    lcrzo_uint16 ipcheck;
    hdrpip.check=0; /*pour le calcul, le checksum doit etre nul*/
    memcpy(buf, &hdrpip, sizeof(lcrzo_hdrpip));
    memcpy(buf+sizeof(lcrzo_hdrpip), ipopt, nboctipopt);
    lcrzo_er(lcrzo_data_checksum(buf, sizeof(lcrzo_hdrpip)+nboctipopt,
				 &ipcheck));
    hdrpip.check=lcrzo_htons(ipcheck);
  }

  /*compose le packet*/
  lcrzo_er(lcrzo_data_initm_data((lcrzo_data)&hdrpip, sizeof(lcrzo_hdrpip),
				 pdataout, pdataoutsize));
  lcrzo_er(lcrzo_data_appendm_data(ipopt, nboctipopt, sizeof(lcrzo_hdrpip),
				   pdataout, pdataoutsize));
  lcrzo_er(lcrzo_data_appendm_data(data, nboctdata,
				   sizeof(lcrzo_hdrpip)+nboctipopt,
				   pdataout, pdataoutsize));

  return(LCRZO_ERR_OK); 
}

/*-------------------------------------------------------------*/
lcrzo_ipl lcrzo_priv_addsthdrpseudo(lcrzo_ipl hdrip_daddr,
				     const lcrzo_ipopt ipopt,
				     lcrzo_uint8 nboctipopt);
lcrzo_ipl lcrzo_priv_addsthdrpseudo(lcrzo_ipl hdrip_daddr,
				     const lcrzo_ipopt ipopt,
				     lcrzo_uint8 nboctipopt)
{ int retour;
  lcrzo_uint8 nbiplaffectes;
  lcrzo_uint8 pointeur;
  lcrzo_ipl ipltab[9];

  /* il n'y a pas d'options IP*/
  if (!nboctipopt) 
  { return(hdrip_daddr);
  }
    
  /*cherche loose source routing*/
  retour=lcrzo_ipopt_decode_lsrr(ipopt, nboctipopt,
				&nbiplaffectes, &pointeur,
				&ipltab[0], &ipltab[1], &ipltab[2], 
				&ipltab[3], &ipltab[4], &ipltab[5], 
				&ipltab[6], &ipltab[7], &ipltab[8]);
  if ( retour!=LCRZO_ERR_OK )
  { /*cherche strict source routing*/
    retour=lcrzo_ipopt_decode_ssrr(ipopt, nboctipopt,
				  &nbiplaffectes, &pointeur,
				  &ipltab[0], &ipltab[1], &ipltab[2], 
				  &ipltab[3], &ipltab[4], &ipltab[5], 
				  &ipltab[6], &ipltab[7], &ipltab[8]);
    if ( retour!=LCRZO_ERR_OK )
    { /*on n'a rien trouve, donc on retourne l'adresse de l'entete IP*/
      return(hdrip_daddr);
    }
  }

  /*on a trouve une option lsrr ou ssrr que l'on analyse*/
  if ( nbiplaffectes>=1 && nbiplaffectes<=9 )
  { if ( pointeur/4 > nbiplaffectes ) /*est arrive au destinataire*/
      return(hdrip_daddr);
    else /*n'a pas encore atteint le destinataire*/
      return(ipltab[nbiplaffectes-1]);
  }

  /*on retourne l'adresse de l'entete IP*/
  return(hdrip_daddr);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ipoptudpdata(lcrzo_hdrlip hdrlip,
				    const lcrzo_ipopt ipopt,
				    lcrzo_uint8 nboctipopt,
				    lcrzo_hdrludp hdrludp,
				    lcrzo_constdata data, 
				    lcrzo_uint16 nboctdata,
				    lcrzo_data *pdataout,
				    lcrzo_int32 *pdataoutsize)
{ lcrzo_data buf;
  lcrzo_uint16 buflen; 
  lcrzo_hdrpudp hdrpudp;
  lcrzo_bool hdr_compfields, hdr_compfield_ipprotocol, hdr_compfield_udplen, hdr_compfield_udpcheck;
  int ret;

  /*parameters verification*/
  if (ipopt==NULL && nboctipopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);
  if ( sizeof(lcrzo_hdrpip)+nboctipopt+
       sizeof(lcrzo_hdrpudp)+nboctdata > 0xFFFF )
    return(LCRZO_ERR_PATOOBIG);

  /*met eventuellement a jour protocole udp*/
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_ipprotocol(&hdr_compfield_ipprotocol));
  if (hdrlip.protocol==LCRZO_HDRLIP_PROTOCOL_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_ipprotocol )
  { hdrlip.protocol=LCRZO_HDRLIP_PROTOCOL_UDP;
  }

  /*met eventuellement a jour len*/
  lcrzo_er(lcrzo_global_get_hdr_cf_udplen(&hdr_compfield_udplen));
  if (hdrludp.len==LCRZO_HDRLUDP_LEN_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_udplen )
  { hdrludp.len=(lcrzo_uint16)( sizeof(lcrzo_hdrpudp)+nboctdata );
  }

  /*conversion de l'entete logique en entete physique*/
  lcrzo_er(lcrzo_hdrpudp_init_hdrludp(hdrludp, &hdrpudp));

  /*calcule le checksum que si il n'est pas deja affecte*/
  lcrzo_er(lcrzo_global_get_hdr_cf_udpcheck(&hdr_compfield_udpcheck));
  if (hdrpudp.check==lcrzo_htons(LCRZO_HDRLUDP_CHECK_DEFVAL) &&
      hdr_compfields &&
      hdr_compfield_udpcheck )
  { lcrzo_hdrpseudo hdrpseudo;
    lcrzo_uint16 udpcheck;
    hdrpseudo.saddr=lcrzo_htonl(hdrlip.saddr);
    /*l'adresse destination doit etre la vraie adresse. Dans le cas des
      packets avec du source routing, il faut prendre l'adresse de l'option*/
    hdrpseudo.daddr=lcrzo_htonl(lcrzo_priv_addsthdrpseudo(
					       hdrlip.daddr,
					       ipopt, nboctipopt));
    hdrpseudo.zeros=0;
    hdrpseudo.protocol=hdrlip.protocol;
    hdrpseudo.len=hdrpudp.len;
    buflen=(lcrzo_uint16)(sizeof(lcrzo_hdrpseudo)+
			  sizeof(lcrzo_hdrpudp)+nboctdata);
    lcrzo_er(lcrzo_data_alloc(buflen, &buf));
    memcpy(buf, &hdrpseudo, sizeof(lcrzo_hdrpseudo));
    memcpy(buf+sizeof(lcrzo_hdrpseudo), &hdrpudp,
	   sizeof(lcrzo_hdrpudp));
    memcpy(buf+sizeof(lcrzo_hdrpseudo)+sizeof(lcrzo_hdrpudp),
	   data, nboctdata);
    ret=lcrzo_data_checksum(buf, buflen, &udpcheck);
    lcrzo_data_free(buf);
    lcrzo_er(ret);
    hdrpudp.check=lcrzo_htons(udpcheck);
  }

  /*compose le packet udp*/
  buflen=(lcrzo_uint16)(sizeof(lcrzo_hdrpudp)+nboctdata);
  lcrzo_er(lcrzo_data_alloc(buflen, &buf));
  memcpy(buf, &hdrpudp, sizeof(lcrzo_hdrpudp));
  memcpy(buf+sizeof(lcrzo_hdrpudp), data, nboctdata);

  ret=lcrzo_packet_initm_ipoptdata(hdrlip, ipopt, nboctipopt,
				   buf, buflen, pdataout, pdataoutsize);
  lcrzo_data_free(buf);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ipopttcpoptdata(lcrzo_hdrlip hdrlip,
				       const lcrzo_ipopt ipopt,
				       lcrzo_uint8 nboctipopt,
				       lcrzo_hdrltcp hdrltcp,
				       const lcrzo_tcpopt tcpopt,
				       lcrzo_uint8 nbocttcpopt,
				       lcrzo_constdata data, 
				       lcrzo_uint16 nboctdata,
				       lcrzo_data *pdataout,
				       lcrzo_int32 *pdataoutsize)
{ lcrzo_data buf;
  lcrzo_uint16 buflen; 
  lcrzo_hdrptcp hdrptcp;
  lcrzo_bool hdr_compfields, hdr_compfield_ipprotocol, hdr_compfield_tcpdoff, hdr_compfield_tcpcheck;
  int ret;

  /*parameters verification*/
  if (ipopt==NULL && nboctipopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (tcpopt==NULL && nbocttcpopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);
  lcrzo_tcpopt_verifbof(nbocttcpopt);
  if ( sizeof(lcrzo_hdrpip)+nboctipopt+
       sizeof(lcrzo_hdrptcp)+nbocttcpopt+nboctdata > 0xFFFF )
    return(LCRZO_ERR_PATOOBIG);

  /*verifie que la taille des options soit un multiple de 4*/
  if (nbocttcpopt%4)
    return(LCRZO_ERR_SPOPTNOTX4);

  /*met eventuellement a jour protocole tcp*/
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_ipprotocol(&hdr_compfield_ipprotocol));
  if (hdrlip.protocol==LCRZO_HDRLIP_PROTOCOL_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_ipprotocol )
  { hdrlip.protocol=LCRZO_HDRLIP_PROTOCOL_TCP;
  }

  /*met eventuellement a jour dataoff*/
  lcrzo_er(lcrzo_global_get_hdr_cf_tcpdoff(&hdr_compfield_tcpdoff));
  if (hdrltcp.doff==LCRZO_HDRLTCP_DOFF_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_tcpdoff ) 
  { hdrltcp.doff=(lcrzo_uint8)( (sizeof(lcrzo_hdrptcp)+nbocttcpopt)/4 );
  }

  /*conversion de l'entete logique en entete physique*/
  lcrzo_er(lcrzo_hdrptcp_init_hdrltcp(hdrltcp, &hdrptcp));

  /*calcule le checksum que si il n'est pas deja affecte*/
  lcrzo_er(lcrzo_global_get_hdr_cf_tcpcheck(&hdr_compfield_tcpcheck));
  if (hdrptcp.check==lcrzo_htons(LCRZO_HDRLTCP_CHECK_DEFVAL) &&
      hdr_compfields &&
      hdr_compfield_tcpcheck)
  { lcrzo_hdrpseudo hdrpseudo;
    lcrzo_uint16 tcpcheck;
    hdrpseudo.saddr=lcrzo_htonl(hdrlip.saddr);
    /*l'adresse destination doit etre la vraie adresse. Dans le cas des
      packets avec du source routing, il faut prendre l'adresse de l'option*/
    hdrpseudo.daddr=lcrzo_htonl(lcrzo_priv_addsthdrpseudo(
					       hdrlip.daddr,
					       ipopt, nboctipopt));
    hdrpseudo.zeros=0;
    hdrpseudo.protocol=hdrlip.protocol;
    hdrpseudo.len=(lcrzo_uint16)lcrzo_htons(sizeof(lcrzo_hdrptcp)+
					    nbocttcpopt+nboctdata);
    buflen=(lcrzo_uint16)(sizeof(lcrzo_hdrpseudo)+
			  sizeof(lcrzo_hdrptcp)+nbocttcpopt+nboctdata);
    lcrzo_er(lcrzo_data_alloc(buflen, &buf));
    memcpy(buf, &hdrpseudo, sizeof(lcrzo_hdrpseudo));
    memcpy(buf+sizeof(lcrzo_hdrpseudo), &hdrptcp, sizeof(lcrzo_hdrptcp));
    memcpy(buf+sizeof(lcrzo_hdrpseudo)+sizeof(lcrzo_hdrptcp), 
	   tcpopt, nbocttcpopt);
    memcpy(buf+sizeof(lcrzo_hdrpseudo)+sizeof(lcrzo_hdrptcp)+nbocttcpopt,
	   data, nboctdata);
    ret=lcrzo_data_checksum(buf, buflen, &tcpcheck);
    lcrzo_data_free(buf);
    lcrzo_er(ret);    
    hdrptcp.check=lcrzo_htons(tcpcheck);
  }

  /*compose le packet tcp*/
  buflen=(lcrzo_uint16)(sizeof(lcrzo_hdrptcp)+nbocttcpopt+nboctdata);
  lcrzo_er(lcrzo_data_alloc(buflen, &buf));
  memcpy(buf, &hdrptcp, sizeof(lcrzo_hdrptcp));
  memcpy(buf+sizeof(lcrzo_hdrptcp), tcpopt, nbocttcpopt);
  memcpy(buf+sizeof(lcrzo_hdrptcp)+nbocttcpopt, data, nboctdata);

  ret=lcrzo_packet_initm_ipoptdata(hdrlip, ipopt, nboctipopt,
				   buf, buflen, pdataout, pdataoutsize);
  lcrzo_data_free(buf);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_icmpdata(lcrzo_hdrlicmp hdrlicmp,
				lcrzo_constdata icmpdata, 
				lcrzo_uint16 icmpdatasize,
				lcrzo_data *pdataout,
				lcrzo_int32 *pdataoutsize)
{ lcrzo_hdrpicmp hdrpicmp;
  lcrzo_uint16 icmpcheck;
  lcrzo_data buf;
  lcrzo_uint16 buflen; 
  lcrzo_bool hdr_compfields, hdr_compfield_icmpcheck;
  int ret;

  /*parameters verification*/
  if (icmpdata==NULL && icmpdatasize) return(LCRZO_ERR_PANULLPTRSIZE);
  if ( sizeof(lcrzo_hdrpip)+icmpdatasize > 0xFFFF )
    return(LCRZO_ERR_PATOOBIG);

  /* convert logical header to physical header */
  lcrzo_er(lcrzo_hdrpicmp_init_hdrlicmp(hdrlicmp, &hdrpicmp));

  /* compute icmp checksum */
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_icmpcheck(&hdr_compfield_icmpcheck));
  if (hdrpicmp.check==lcrzo_htons(LCRZO_HDRLICMP_CHECK_DEFVAL) &&
      hdr_compfields &&
      hdr_compfield_icmpcheck )
  { buflen=(lcrzo_uint16)(sizeof(lcrzo_hdrpicmp)+icmpdatasize);
    lcrzo_er(lcrzo_data_alloc(buflen, &buf));
    memcpy(buf, &hdrpicmp, sizeof(lcrzo_hdrpicmp));
    memcpy(buf+sizeof(lcrzo_hdrpicmp), icmpdata, icmpdatasize);
    ret=lcrzo_data_checksum(buf, buflen, &icmpcheck);
    lcrzo_data_free(buf);
    lcrzo_er(ret);
    hdrpicmp.check=lcrzo_htons(icmpcheck);
  }

  /* compose the packet */
  buflen=(lcrzo_uint16)(sizeof(lcrzo_hdrpicmp)+icmpdatasize);
  lcrzo_er(lcrzo_data_alloc(buflen, &buf));
  memcpy(buf, &hdrpicmp, sizeof(lcrzo_hdrpicmp));
  memcpy(buf+sizeof(lcrzo_hdrpicmp), icmpdata, icmpdatasize);

  /* set output values */
  if (pdataoutsize!=NULL) *pdataoutsize=buflen;
  if (pdataout!=NULL)
  { *pdataout=buf;
  }
  else
  { lcrzo_data_free(buf);
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ipopticmpdata(lcrzo_hdrlip hdrlip,
				     const lcrzo_ipopt ipopt,
				     lcrzo_uint8 nboctipopt,
				     lcrzo_hdrlicmp hdrlicmp,
				     lcrzo_constdata data, 
				     lcrzo_uint16 nboctdata,
				     lcrzo_data *pdataout,
				     lcrzo_int32 *pdataoutsize)
{ lcrzo_hdrpicmp hdrpicmp;
  lcrzo_uint16 icmpcheck;
  lcrzo_data buf;
  lcrzo_uint16 buflen; 
  lcrzo_bool hdr_compfields, hdr_compfield_ipprotocol, hdr_compfield_icmpcheck;
  int ret;

  /*parameters verification*/
  if (ipopt==NULL && nboctipopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);
  if ( sizeof(lcrzo_hdrpip)+nboctipopt+
       sizeof(lcrzo_hdrpicmp)+nboctdata > 0xFFFF )
    return(LCRZO_ERR_PATOOBIG);

  /*met eventuellement a jour protocole icp*/
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_ipprotocol(&hdr_compfield_ipprotocol));
  if (hdrlip.protocol==LCRZO_HDRLIP_PROTOCOL_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_ipprotocol )
  { hdrlip.protocol=LCRZO_HDRLIP_PROTOCOL_ICMP;
  }

  /*conversion de l'entete logique en entete physique*/
  lcrzo_er(lcrzo_hdrpicmp_init_hdrlicmp(hdrlicmp, &hdrpicmp));

  /*calcule le checksum que si il n'est pas deja affecte*/
  lcrzo_er(lcrzo_global_get_hdr_cf_icmpcheck(&hdr_compfield_icmpcheck));
  if (hdrpicmp.check==lcrzo_htons(LCRZO_HDRLICMP_CHECK_DEFVAL) &&
      hdr_compfields &&
      hdr_compfield_icmpcheck )
  { buflen=(lcrzo_uint16)(sizeof(lcrzo_hdrpicmp)+nboctdata);
    lcrzo_er(lcrzo_data_alloc(buflen, &buf));
    memcpy(buf, &hdrpicmp, sizeof(lcrzo_hdrpicmp));
    memcpy(buf+sizeof(lcrzo_hdrpicmp), data, nboctdata);
    ret=lcrzo_data_checksum(buf, sizeof(lcrzo_hdrpicmp)+
			    nboctdata, &icmpcheck);
    lcrzo_data_free(buf);
    lcrzo_er(ret);
    hdrpicmp.check=lcrzo_htons(icmpcheck);
  }

  /*compose le packet icmp*/
  buflen=(lcrzo_uint16)(sizeof(lcrzo_hdrpicmp)+nboctdata);
  lcrzo_er(lcrzo_data_alloc(buflen, &buf));
  memcpy(buf, &hdrpicmp, sizeof(lcrzo_hdrpicmp));
  memcpy(buf+sizeof(lcrzo_hdrpicmp), data, nboctdata);

  ret=lcrzo_packet_initm_ipoptdata(hdrlip, ipopt, nboctipopt,
				  buf, buflen, pdataout, pdataoutsize);
  lcrzo_data_free(buf);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ethdata(lcrzo_hdrleth hdrleth,
			       lcrzo_constdata data, 
			       lcrzo_uint16 nboctdata,
			       lcrzo_data *pdataout,
			       lcrzo_int32 *pdataoutsize)
{ lcrzo_hdrpeth hdrpeth;

  /*parameters verification*/
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);

  /*conversion de l'entete logique en entete physique*/
  lcrzo_er(lcrzo_hdrpeth_init_hdrleth(hdrleth, &hdrpeth));

  /*compose le packet*/
  lcrzo_er(lcrzo_data_initm_data((lcrzo_data)&hdrpeth, sizeof(lcrzo_hdrpeth),
				 pdataout, pdataoutsize));
  lcrzo_er(lcrzo_data_appendm_data(data, nboctdata, sizeof(lcrzo_hdrpeth),
				   pdataout, pdataoutsize));  
  return(LCRZO_ERR_OK); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ethipoptdata(lcrzo_hdrleth hdrleth,
				    lcrzo_hdrlip hdrlip,
				    const lcrzo_ipopt ipopt,
				    lcrzo_uint8 nboctipopt,
				    lcrzo_constdata data, 
				    lcrzo_uint16 nboctdata,
				    lcrzo_data *pdataout,
				    lcrzo_int32 *pdataoutsize)
{ lcrzo_data buf;
  lcrzo_int32 buflen;
  lcrzo_bool hdr_compfields, hdr_compfield_ethtype;
  int ret;

  /*parameters verification*/
  if (ipopt==NULL && nboctipopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);
  lcrzo_ipopt_verifbof(nboctipopt);

  /*ajout eventuel du type*/
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_ethtype(&hdr_compfield_ethtype));
  if (hdrleth.type==LCRZO_HDRLETH_TYPE_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_ethtype )
  { hdrleth.type=LCRZO_HDRLETH_TYPE_IP;
  }

  /*compose le packet*/
  lcrzo_er(lcrzo_packet_initm_ipoptdata(hdrlip, ipopt, nboctipopt,
					data, nboctdata, 
					&buf, &buflen));
  if ( buflen > 0xFFFF ) return(LCRZO_ERR_PATOOBIG);
  ret=lcrzo_packet_initm_ethdata(hdrleth, buf, (lcrzo_uint16)buflen,
				 pdataout, pdataoutsize);
  lcrzo_data_free(buf);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ethipoptudpdata(lcrzo_hdrleth hdrleth,
				       lcrzo_hdrlip hdrlip,
				       const lcrzo_ipopt ipopt,
				       lcrzo_uint8 nboctipopt,
				       lcrzo_hdrludp hdrludp,
				       lcrzo_constdata data, 
				       lcrzo_uint16 nboctdata,
				       lcrzo_data *pdataout,
				       lcrzo_int32 *pdataoutsize)
{ lcrzo_data buf;
  lcrzo_int32 buflen;
  lcrzo_bool hdr_compfields, hdr_compfield_ethtype;
  int ret;

  /*parameters verification*/
  if (ipopt==NULL && nboctipopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);
  lcrzo_ipopt_verifbof(nboctipopt);

  /*ajout eventuel du type*/
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_ethtype(&hdr_compfield_ethtype));
  if (hdrleth.type==LCRZO_HDRLETH_TYPE_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_ethtype )
  { hdrleth.type=LCRZO_HDRLETH_TYPE_IP;
  }

  /*compose le packet*/
  lcrzo_er(lcrzo_packet_initm_ipoptudpdata(hdrlip, ipopt, nboctipopt, hdrludp,
					   data, nboctdata,
					   &buf, &buflen));
  if ( buflen > 0xFFFF ) return(LCRZO_ERR_PATOOBIG);
  ret=lcrzo_packet_initm_ethdata(hdrleth, buf, (lcrzo_uint16)buflen,
				 pdataout, pdataoutsize);
  lcrzo_data_free(buf);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ethipopttcpoptdata(lcrzo_hdrleth hdrleth,
					  lcrzo_hdrlip hdrlip,
					  const lcrzo_ipopt ipopt,
					  lcrzo_uint8 nboctipopt,
					  lcrzo_hdrltcp hdrltcp,
					  const lcrzo_tcpopt tcpopt,
					  lcrzo_uint8 nbocttcpopt,
					  lcrzo_constdata data, 
					  lcrzo_uint16 nboctdata,
					  lcrzo_data *pdataout,
					  lcrzo_int32 *pdataoutsize)
{ lcrzo_data buf;
  lcrzo_int32 buflen;
  lcrzo_bool hdr_compfields, hdr_compfield_ethtype;
  int ret;
  
  /*parameters verification*/
  if (ipopt==NULL && nboctipopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (tcpopt==NULL && nbocttcpopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);
  lcrzo_ipopt_verifbof(nboctipopt);
  lcrzo_tcpopt_verifbof(nbocttcpopt);

  /*ajout eventuel du type*/
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_ethtype(&hdr_compfield_ethtype));
  if (hdrleth.type==LCRZO_HDRLETH_TYPE_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_ethtype )
  { hdrleth.type=LCRZO_HDRLETH_TYPE_IP;
  }

  /*compose le packet*/
  lcrzo_er(lcrzo_packet_initm_ipopttcpoptdata(hdrlip, ipopt, nboctipopt,
					      hdrltcp,
					      tcpopt, nbocttcpopt,
					      data, nboctdata, 
					      &buf, &buflen));
  if ( buflen > 0xFFFF ) return(LCRZO_ERR_PATOOBIG);
  ret=lcrzo_packet_initm_ethdata(hdrleth, buf, (lcrzo_uint16)buflen,
				 pdataout, pdataoutsize);
  lcrzo_data_free(buf);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_initm_ethipopticmpdata(lcrzo_hdrleth hdrleth,
					lcrzo_hdrlip hdrlip,
					const lcrzo_ipopt ipopt,
					lcrzo_uint8 nboctipopt,
					lcrzo_hdrlicmp hdrlicmp,
					lcrzo_constdata data, 
					lcrzo_uint16 nboctdata,
					lcrzo_data *pdataout,
					lcrzo_int32 *pdataoutsize)
{ lcrzo_data buf;
  lcrzo_int32 buflen;
  lcrzo_bool hdr_compfields, hdr_compfield_ethtype;
  int ret;

  /*parameters verification*/
  if (ipopt==NULL && nboctipopt) return(LCRZO_ERR_PANULLPTRSIZE);
  if (data==NULL && nboctdata) return(LCRZO_ERR_PANULLPTRSIZE);
  lcrzo_ipopt_verifbof(nboctipopt);

  /*ajout eventuel du type*/
  lcrzo_er(lcrzo_global_get_hdr_compfields(&hdr_compfields));
  lcrzo_er(lcrzo_global_get_hdr_cf_ethtype(&hdr_compfield_ethtype));
  if (hdrleth.type==LCRZO_HDRLETH_TYPE_DEFVAL &&
      hdr_compfields &&
      hdr_compfield_ethtype )
  { hdrleth.type=LCRZO_HDRLETH_TYPE_IP;
  }

  /*compose le packet*/
  lcrzo_er(lcrzo_packet_initm_ipopticmpdata(hdrlip, ipopt, nboctipopt,
					   hdrlicmp,
					   data, nboctdata,
					    &buf, &buflen));
  if ( buflen > 0xFFFF ) return(LCRZO_ERR_PATOOBIG);
  ret=lcrzo_packet_initm_ethdata(hdrleth, buf, (lcrzo_uint16)buflen,
                                pdataout, pdataoutsize);
  lcrzo_data_free(buf);
  return(ret);
}


/*-------------------------------------------------------------*/
int lcrzo_packet_initm_etharp(lcrzo_hdrleth hdrleth,
			      lcrzo_hdrlarp hdrlarp,
			      lcrzo_data *pdataout,
			      lcrzo_int32 *pdataoutsize)
{ lcrzo_hdrpeth hdrpeth;
  lcrzo_hdrparp hdrparp;

  /*conversion de l'entete logique en entete physique*/
  lcrzo_er(lcrzo_hdrpeth_init_hdrleth(hdrleth, &hdrpeth));
  lcrzo_er(lcrzo_hdrparp_init_hdrlarp(hdrlarp, &hdrparp));

  /*compose le packet*/
  lcrzo_er(lcrzo_data_initm_data((lcrzo_data)&hdrpeth, sizeof(lcrzo_hdrpeth),
                                 pdataout, pdataoutsize));
  lcrzo_er(lcrzo_data_appendm_data((lcrzo_data)&hdrparp, sizeof(lcrzo_hdrparp),
				   sizeof(lcrzo_hdrpeth),
				   pdataout, pdataoutsize));
  return(LCRZO_ERR_OK); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ipoptdata(lcrzo_constdata packet,
				   lcrzo_int32 nboctpacket,
				   lcrzo_hdrlip *phdrlip,
				   lcrzo_ipopt ipopt,
				   lcrzo_uint8 *pnboctipopt,
				   lcrzo_data *pdata,
				   lcrzo_uint16 *pdatasize)
{ lcrzo_hdrpip hdrpip;
  lcrzo_uint8 nboctipopt;
  lcrzo_uint16 nboctdata;
 
  /*parameters verification*/
  if (packet==NULL && nboctpacket) return(LCRZO_ERR_PANULLPTRSIZE);
  /*entete incomplet*/
  if (nboctpacket<0) return(LCRZO_ERR_PATOOLOW);
  if ((lcrzo_uint32)nboctpacket<sizeof(lcrzo_hdrpip))
    return(LCRZO_ERR_OKNOTDECODED);

  /*entete IP*/
  memcpy(&hdrpip, packet, sizeof(lcrzo_hdrpip));
  if ( hdrpip.version != 4 ) return(LCRZO_ERR_OKNOTDECODED);
  if ( phdrlip!=NULL )
  { lcrzo_er(lcrzo_hdrlip_init_hdrpip(hdrpip, phdrlip));
  }

  /*correction de l'entete IP*/
  if (lcrzo_ntohs(hdrpip.totlen)<nboctpacket)
  { /*les packets sniffes contiennent des octets inutiles en fin*/
    nboctpacket=lcrzo_ntohs(hdrpip.totlen);
  }

  /*options IP*/
  if (hdrpip.ihl>5)
  { nboctipopt=(lcrzo_uint8)( (hdrpip.ihl-5)*4 );
    if ((lcrzo_int32)(nboctipopt+sizeof(lcrzo_hdrpip))>nboctpacket)
      return(LCRZO_ERR_OKNOTDECODED);
    if (ipopt!=NULL) memcpy(ipopt, packet+sizeof(lcrzo_hdrpip), nboctipopt);
  }
  else if (hdrpip.ihl<5)
  { return(LCRZO_ERR_OKNOTDECODED);
  }
  else
  { nboctipopt=0;
  }
  if (pnboctipopt!=NULL) *pnboctipopt=nboctipopt;

  /*donnees IP*/
  if (nboctpacket - 4*hdrpip.ihl > 0xFFFF)
    return(LCRZO_ERR_OKNOTDECODED);
  else
    nboctdata=(lcrzo_uint16)(nboctpacket - 4*hdrpip.ihl);
  lcrzo_er(lcrzo_priv_data_u16_initm_data(packet + 4*hdrpip.ihl, nboctdata,
					  pdata, pdatasize));

  return(LCRZO_ERR_OK); 
}


/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_udpdata(lcrzo_constdata packet,
				 lcrzo_int32 nboctpacket,
				 lcrzo_hdrludp *phdrludp,
				 lcrzo_data *pdata,
				 lcrzo_uint16 *pdatasize)
{ lcrzo_uint16 nboctdata;

  /*parameters verification*/
  if (packet==NULL && nboctpacket) return(LCRZO_ERR_PANULLPTRSIZE);
  /*entete incomplet*/
  if (nboctpacket<0) return(LCRZO_ERR_PATOOLOW);
  if ((lcrzo_uint32)nboctpacket<sizeof(lcrzo_hdrpudp))
    return(LCRZO_ERR_OKNOTDECODED);

  /*affectation de l'entete UDP*/
  if ( phdrludp!=NULL )
  { lcrzo_hdrpudp hdrpudp;
    memcpy(&hdrpudp, packet, sizeof(lcrzo_hdrpudp));
    lcrzo_er(lcrzo_hdrludp_init_hdrpudp(hdrpudp, phdrludp));
  }

  /*donnees UDP*/
  if ( nboctpacket-sizeof(lcrzo_hdrpudp) > 0xFFFF )
    return(LCRZO_ERR_OKNOTDECODED);
  else
    nboctdata=(lcrzo_uint16)(nboctpacket-sizeof(lcrzo_hdrpudp));
  lcrzo_er(lcrzo_priv_data_u16_initm_data(packet+sizeof(lcrzo_hdrpudp),
					  nboctdata,
					  pdata, pdatasize));

  return(LCRZO_ERR_OK); 
}


/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_tcpoptdata(lcrzo_constdata packet, 
				    lcrzo_int32 nboctpacket,
				    lcrzo_hdrltcp *phdrltcp,
				    lcrzo_tcpopt tcpopt,
				    lcrzo_uint8 *pnbocttcpopt,
				    lcrzo_data *pdata,
				    lcrzo_uint16 *pdatasize)
{ lcrzo_hdrptcp hdrptcp;
  lcrzo_uint8 nbocttcpopt;
  lcrzo_uint16 nboctdata;

  /*parameters verification*/
  if (packet==NULL && nboctpacket) return(LCRZO_ERR_PANULLPTRSIZE);
  /*entete incomplet*/
  if (nboctpacket<0) return(LCRZO_ERR_PATOOLOW);
  if ((lcrzo_uint32)nboctpacket<sizeof(lcrzo_hdrptcp))
    return(LCRZO_ERR_OKNOTDECODED);

  /*entete TCP*/
  memcpy(&hdrptcp, packet, sizeof(lcrzo_hdrptcp));
  if ( phdrltcp!=NULL )
  { lcrzo_er(lcrzo_hdrltcp_init_hdrptcp(hdrptcp, phdrltcp));
  }

  /*options TCP*/
  if (hdrptcp.doff>5)
  { nbocttcpopt=(lcrzo_uint8)( (hdrptcp.doff-5)*4 );
    if ((lcrzo_int32)(nbocttcpopt+sizeof(lcrzo_hdrptcp))>nboctpacket)
      return(LCRZO_ERR_OKNOTDECODED);
    if(tcpopt!=NULL) memcpy(tcpopt, packet+sizeof(lcrzo_hdrptcp), nbocttcpopt);
  }
  else if (hdrptcp.doff<5)
  { return(LCRZO_ERR_OKNOTDECODED);
  }
  else
  { nbocttcpopt=0;
  }
  if (pnbocttcpopt!=NULL) *pnbocttcpopt=nbocttcpopt;

  /*donnees TCP*/
  if ( nboctpacket-4*hdrptcp.doff > 0xFFFF )
    return(LCRZO_ERR_OKNOTDECODED);
  else
    nboctdata=(lcrzo_uint16)(nboctpacket-4*hdrptcp.doff);
   lcrzo_er(lcrzo_priv_data_u16_initm_data(packet+4*hdrptcp.doff, nboctdata,
					   pdata, pdatasize));

  return(LCRZO_ERR_OK); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_icmpdata(lcrzo_constdata packet,
				  lcrzo_int32 nboctpacket,
				  lcrzo_hdrlicmp *phdrlicmp,
				  lcrzo_data *pdata,
				  lcrzo_uint16 *pdatasize)
{ lcrzo_uint16 nboctdata;

  /*parameters verification*/
  if (packet==NULL && nboctpacket) return(LCRZO_ERR_PANULLPTRSIZE);
  /*entete incomplet*/
  if (nboctpacket<0) return(LCRZO_ERR_PATOOLOW);
  if ((lcrzo_uint32)nboctpacket<sizeof(lcrzo_hdrpicmp))
    return(LCRZO_ERR_OKNOTDECODED);

  /*affectation de l'entete ICMP*/
  if ( phdrlicmp!=NULL )
  { lcrzo_hdrpicmp hdrpicmp;
    memcpy(&hdrpicmp, packet, sizeof(lcrzo_hdrpicmp));
    lcrzo_er(lcrzo_hdrlicmp_init_hdrpicmp(hdrpicmp, phdrlicmp));
  }

  /*donnees ICMP*/
  if ( nboctpacket-sizeof(lcrzo_hdrpicmp) > 0xFFFF )
    return(LCRZO_ERR_OKNOTDECODED);
  else
    nboctdata=(lcrzo_uint16)(nboctpacket-sizeof(lcrzo_hdrpicmp));
  lcrzo_er(lcrzo_priv_data_u16_initm_data(packet+sizeof(lcrzo_hdrpicmp),
					  nboctdata,
					  pdata, pdatasize));

  return(LCRZO_ERR_OK); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ethdata(lcrzo_constdata packet,
				 lcrzo_int32 nboctpacket,
				 lcrzo_hdrleth *phdrleth,
				 lcrzo_data *pdata,
				 lcrzo_uint16 *pdatasize)
{ lcrzo_uint16 nboctdata;

  /*parameters verification*/
  if (packet==NULL && nboctpacket) return(LCRZO_ERR_PANULLPTRSIZE);
  /*entete incomplet*/
  if (nboctpacket<0) return(LCRZO_ERR_PATOOLOW);
  if ((lcrzo_uint32)nboctpacket<sizeof(lcrzo_hdrpeth))
    return(LCRZO_ERR_OKNOTDECODED);

  /*affectation de l'entete ETH*/
  if ( phdrleth!=NULL )
  { lcrzo_hdrpeth hdrpeth;
    memcpy(&hdrpeth, packet, sizeof(lcrzo_hdrpeth));
    lcrzo_er(lcrzo_hdrleth_init_hdrpeth(hdrpeth, phdrleth));
  }

  /*donnees ETH*/
  if ( nboctpacket-sizeof(lcrzo_hdrpeth) > 0xFFFF )
    return(LCRZO_ERR_OKNOTDECODED);
  else
    nboctdata=(lcrzo_uint16)(nboctpacket-sizeof(lcrzo_hdrpeth));
  lcrzo_er(lcrzo_priv_data_u16_initm_data(packet+sizeof(lcrzo_hdrpeth),
					  nboctdata,
					  pdata, pdatasize));

  return(LCRZO_ERR_OK); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decode_arp(lcrzo_constdata packet,
			    lcrzo_int32 nboctpacket,
			    lcrzo_hdrlarp *phdrlarp)
{
  /*parameters verification*/
  if (packet==NULL && nboctpacket) return(LCRZO_ERR_PANULLPTRSIZE);
  /*entete incomplet*/
  if (nboctpacket<0) return(LCRZO_ERR_PATOOLOW);
  if ((lcrzo_uint32)nboctpacket<sizeof(lcrzo_hdrparp))
    return(LCRZO_ERR_OKNOTDECODED);

  /*affectation de l'entete ARP*/
  if ( phdrlarp!=NULL )
  { lcrzo_hdrparp hdrparp;
    memcpy(&hdrparp, packet, sizeof(lcrzo_hdrparp));
    lcrzo_er(lcrzo_hdrlarp_init_hdrparp(hdrparp, phdrlarp));
  }

  return(LCRZO_ERR_OK); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ipoptudpdata(lcrzo_constdata packet, 
				      lcrzo_int32 nboctpacket,
				      lcrzo_hdrlip *phdrlip,
				      lcrzo_ipopt ipopt,
				      lcrzo_uint8 *pnboctipopt,
				      lcrzo_hdrludp *phdrludp,
				      lcrzo_data *pdata,
				      lcrzo_uint16 *pdatasize)
{ lcrzo_data ipdata;
  lcrzo_uint16 nboctipdata;
  lcrzo_hdrlip hdrliplocal;
  int ret;

  /*decode pour l'entete IP*/
  lcrzo_er(lcrzo_packet_decodem_ipoptdata(packet, nboctpacket,
					  &hdrliplocal, ipopt, pnboctipopt,
					  &ipdata, &nboctipdata));

  /*si l'entete IP est non NULL on le copie */
  if ( phdrlip!=NULL )
  { memcpy(phdrlip, &hdrliplocal, sizeof(lcrzo_hdrlip));
  }

  /*decode le contenu*/
  if ( hdrliplocal.offsetfrag )
  { lcrzo_data_free(ipdata);
    return(LCRZO_ERR_OKNOTDECODED); /*ne sait pas decoder les fragments*/
  }
  if ( hdrliplocal.protocol != LCRZO_HDRLIP_PROTOCOL_UDP )
  { lcrzo_data_free(ipdata);
    return(LCRZO_ERR_OKNOTDECODED);
  }
  ret=lcrzo_packet_decodem_udpdata(ipdata, nboctipdata,
				   phdrludp,
				   pdata, pdatasize);
  lcrzo_data_free(ipdata);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ipopttcpoptdata(lcrzo_constdata packet, 
					 lcrzo_int32 nboctpacket,
					 lcrzo_hdrlip *phdrlip,
					 lcrzo_ipopt ipopt,
					 lcrzo_uint8 *pnboctipopt,
					 lcrzo_hdrltcp *phdrltcp,
					 lcrzo_tcpopt tcpopt,
					 lcrzo_uint8 *pnbocttcpopt,
					 lcrzo_data *pdata,
					 lcrzo_uint16 *pdatasize)
{ lcrzo_data ipdata;
  lcrzo_uint16 nboctipdata;
  lcrzo_hdrlip hdrliplocal;
  int ret;

  /*decode pour l'entete IP*/
  lcrzo_er(lcrzo_packet_decodem_ipoptdata(packet, nboctpacket,
					  &hdrliplocal,
					  ipopt, pnboctipopt,
					  &ipdata, &nboctipdata));

  /*si l'entete IP est non NULL on le copie */
  if ( phdrlip!=NULL )
  { memcpy(phdrlip, &hdrliplocal, sizeof(lcrzo_hdrlip));
  }

  /*decode le contenu*/
  if ( hdrliplocal.offsetfrag )
  { lcrzo_data_free(ipdata);
    return(LCRZO_ERR_OKNOTDECODED); /*ne sait pas decoder les fragments*/
  }
  if ( hdrliplocal.protocol != LCRZO_HDRLIP_PROTOCOL_TCP )
  { lcrzo_data_free(ipdata);
    return(LCRZO_ERR_OKNOTDECODED);
  }
  ret=lcrzo_packet_decodem_tcpoptdata(ipdata, nboctipdata,
				      phdrltcp, tcpopt, pnbocttcpopt,
				      pdata, pdatasize);
  lcrzo_data_free(ipdata);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ipopticmpdata(lcrzo_constdata packet, 
				       lcrzo_int32 nboctpacket,
				       lcrzo_hdrlip *phdrlip,
				       lcrzo_ipopt ipopt,
				       lcrzo_uint8 *pnboctipopt,
				       lcrzo_hdrlicmp *phdrlicmp,
				       lcrzo_data *pdata,
				       lcrzo_uint16 *pdatasize)
{ lcrzo_data ipdata;
  lcrzo_uint16 nboctipdata;
  lcrzo_hdrlip hdrliplocal;
  int ret;

  /*decode pour l'entete IP*/
  lcrzo_er(lcrzo_packet_decodem_ipoptdata(packet, nboctpacket,
					  &hdrliplocal, ipopt, pnboctipopt,
					  &ipdata, &nboctipdata));

  /*si l'entete IP est non NULL on le copie */
  if ( phdrlip!=NULL )
  { memcpy(phdrlip, &hdrliplocal, sizeof(lcrzo_hdrlip));
  }

  /*decode le contenu*/
  if ( hdrliplocal.offsetfrag )
  { lcrzo_data_free(ipdata);
    return(LCRZO_ERR_OKNOTDECODED); /*ne sait pas decoder les fragments*/
  }
  if ( hdrliplocal.protocol != LCRZO_HDRLIP_PROTOCOL_ICMP )
  { lcrzo_data_free(ipdata);
    return(LCRZO_ERR_OKNOTDECODED);
  }
  ret=lcrzo_packet_decodem_icmpdata(ipdata, nboctipdata,
				    phdrlicmp,
				    pdata, pdatasize);
  lcrzo_data_free(ipdata);
  return(ret); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ethipoptdata(lcrzo_constdata packet, 
				      lcrzo_int32 nboctpacket,
				      lcrzo_hdrleth *phdrleth,
				      lcrzo_hdrlip *phdrlip,
				      lcrzo_ipopt ipopt,
				      lcrzo_uint8 *pnboctipopt,
				      lcrzo_data *pdata,
				      lcrzo_uint16 *pdatasize)
{ lcrzo_data ethdata;
  lcrzo_uint16 nboctethdata;
  lcrzo_hdrleth hdrlethlocal;
  int ret;

  /*decode pour l'entete ETH*/
  lcrzo_er(lcrzo_packet_decodem_ethdata(packet, nboctpacket,
					&hdrlethlocal,
					&ethdata, &nboctethdata));
  
  /*si l'entete ETH est non NULL on le copie */
  if ( phdrleth!=NULL )
  { memcpy(phdrleth, &hdrlethlocal, sizeof(lcrzo_hdrleth));
  }

  /*decode le contenu*/
  if ( hdrlethlocal.type != LCRZO_HDRLETH_TYPE_IP )
  { lcrzo_data_free(ethdata);
    return(LCRZO_ERR_OKNOTDECODED);
  }
  ret=lcrzo_packet_decodem_ipoptdata(ethdata, nboctethdata,
				     phdrlip, ipopt, pnboctipopt,
				     pdata, pdatasize);
  lcrzo_data_free(ethdata);
  return(ret); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ethipoptudpdata(lcrzo_constdata packet,
					 lcrzo_int32 nboctpacket,
					 lcrzo_hdrleth *phdrleth,
					 lcrzo_hdrlip *phdrlip,
					 lcrzo_ipopt ipopt,
					 lcrzo_uint8 *pnboctipopt,
					 lcrzo_hdrludp *phdrludp,
					 lcrzo_data *pdata,
					 lcrzo_uint16 *pdatasize)
{ lcrzo_data ethdata;
  lcrzo_uint16 nboctethdata;
  lcrzo_hdrleth hdrlethlocal;
  int ret;
 
  /*decode pour l'entete ETH*/
  lcrzo_er(lcrzo_packet_decodem_ethdata(packet, nboctpacket,
					&hdrlethlocal,
					&ethdata, &nboctethdata));

  /*si l'entete ETH est non NULL on le copie */
  if ( phdrleth!=NULL )
  { memcpy(phdrleth, &hdrlethlocal, sizeof(lcrzo_hdrleth));
  }

  /*decode le contenu*/
  if ( hdrlethlocal.type != LCRZO_HDRLETH_TYPE_IP )
  { lcrzo_data_free(ethdata);
    return(LCRZO_ERR_OKNOTDECODED);
  }
  ret=lcrzo_packet_decodem_ipoptudpdata(ethdata, nboctethdata,
					phdrlip, ipopt, pnboctipopt,
					phdrludp,
					pdata, pdatasize);
  lcrzo_data_free(ethdata);
  return(ret); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ethipopttcpoptdata(lcrzo_constdata packet,
					    lcrzo_int32 nboctpacket,
					    lcrzo_hdrleth *phdrleth,
					    lcrzo_hdrlip *phdrlip,
					    lcrzo_ipopt ipopt,
					    lcrzo_uint8 *pnboctipopt,
					    lcrzo_hdrltcp *phdrltcp,
					    lcrzo_tcpopt tcpopt,
					    lcrzo_uint8 *pnbocttcpopt,
					    lcrzo_data *pdata,
					    lcrzo_uint16 *pdatasize)
{ lcrzo_data ethdata;
  lcrzo_uint16 nboctethdata;
  lcrzo_hdrleth hdrlethlocal;
  int ret;

  /*decode pour l'entete ETH*/
  lcrzo_er(lcrzo_packet_decodem_ethdata(packet, nboctpacket,
					&hdrlethlocal,
					&ethdata, &nboctethdata));

  /*si l'entete ETH est non NULL on le copie */
  if ( phdrleth!=NULL )
  { memcpy(phdrleth, &hdrlethlocal, sizeof(lcrzo_hdrleth));
  }

  /*decode le contenu*/
  if ( hdrlethlocal.type != LCRZO_HDRLETH_TYPE_IP )
  { lcrzo_data_free(ethdata);
    return(LCRZO_ERR_OKNOTDECODED);
  }
  ret=lcrzo_packet_decodem_ipopttcpoptdata(ethdata, nboctethdata,
					   phdrlip,
					   ipopt, pnboctipopt,
					   phdrltcp,
					   tcpopt, pnbocttcpopt,
					   pdata, pdatasize);
  lcrzo_data_free(ethdata);
  return(ret); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decodem_ethipopticmpdata(lcrzo_constdata packet,
					  lcrzo_int32 nboctpacket,
					  lcrzo_hdrleth *phdrleth,
					  lcrzo_hdrlip *phdrlip,
					  lcrzo_ipopt ipopt,
					  lcrzo_uint8 *pnboctipopt,
					  lcrzo_hdrlicmp *phdrlicmp,
					  lcrzo_data *pdata,
					  lcrzo_uint16 *pdatasize)
{ lcrzo_data ethdata;
  lcrzo_uint16 nboctethdata;
  lcrzo_hdrleth hdrlethlocal;
  int ret;

  /*decode pour l'entete ETH*/
  lcrzo_er(lcrzo_packet_decodem_ethdata(packet, nboctpacket,
					&hdrlethlocal,
					&ethdata, &nboctethdata));

  /*si l'entete ETH est non NULL on le copie */
  if ( phdrleth!=NULL )
  { memcpy(phdrleth, &hdrlethlocal, sizeof(lcrzo_hdrleth));
  }

  /*decode le contenu*/
  if ( hdrlethlocal.type != LCRZO_HDRLETH_TYPE_IP )
  { lcrzo_data_free(ethdata);
    return(LCRZO_ERR_OKNOTDECODED);
  }
  ret=lcrzo_packet_decodem_ipopticmpdata(ethdata, nboctethdata,
					 phdrlip, ipopt, pnboctipopt,
					 phdrlicmp,
					 pdata, pdatasize);
  lcrzo_data_free(ethdata);
  return(ret); 
}

/*-------------------------------------------------------------*/
int lcrzo_packet_decode_etharp(lcrzo_constdata packet,
			       lcrzo_int32 nboctpacket,
			       lcrzo_hdrleth *phdrleth,
			       lcrzo_hdrlarp *phdrlarp)
{ lcrzo_data ethdata;
  lcrzo_uint16 nboctethdata;
  lcrzo_hdrleth hdrlethlocal;
  int ret;

  /*decode pour l'entete ETH*/
  lcrzo_er(lcrzo_packet_decodem_ethdata(packet, nboctpacket,
					&hdrlethlocal,
					&ethdata, &nboctethdata));

  /*si l'entete ETH est non NULL on le copie */
  if ( phdrleth!=NULL )
  { memcpy(phdrleth, &hdrlethlocal, sizeof(lcrzo_hdrleth));
  }

  /*decode le contenu*/
  if ( hdrlethlocal.type != LCRZO_HDRLETH_TYPE_ARP && 
       hdrlethlocal.type != LCRZO_HDRLETH_TYPE_RARP)
  { lcrzo_data_free(ethdata);
    return(LCRZO_ERR_OKNOTDECODED);
  }
  ret=lcrzo_packet_decode_arp(ethdata, nboctethdata, phdrlarp);
  lcrzo_data_free(ethdata);
  return(LCRZO_ERR_OK); 
}

