/* This file is part of Lcrzo.
*/

/*-------------------------------------------------------------*/
#if LCRZODEF_LIBNETINSTALLED==1
#include <libnet.h>
int lcrzo_priv_spoof_init_eth(lcrzo_spoof *pspoof,
			        const lcrzo_device device)
{ 
  lcrzo_er(lcrzo_device_init(device, pspoof->device));
  pspoof->plli=libnet_open_link_interface(pspoof->device, err_buf);
  if ( pspoof->plli==NULL )
  { return(LCRZO_ERR_FULIBNETOPENLINKINT);
  }
  pspoof->fd=pspoof->plli->fd; /* for lcrzo_spoof_get_fd */
  return(LCRZO_ERR_OK);
}
int lcrzo_priv_spoof_eth(lcrzo_spoof *pspoof,
			   const lcrzo_device device, 
			   lcrzo_constdata packet, 
			   lcrzo_int32 nboctpacket)
{ int retour;
  lcrzo_data paq;
  char err_buf[LIBNET_ERRBUF_SIZE];

  /*copy because car libnet n'est pas const*/
  lcrzo_er(lcrzo_data_initm_data(packet, nboctpacket, &paq, NULL));
  retour=libnet_write_link_layer(pspoof->plli, (lcrzo_uint8*)device,
				 paq, nboctpacket);
  lcrzo_data_free(paq);
  if ( retour == -1 )
  { return(LCRZO_ERR_FULIBNETWRITELL);
  }

  return(LCRZO_ERR_OK);
}
int lcrzo_priv_spoof_close_eth(lcrzo_spoof *pspoof)
{ int retour;
  
  /*fermeture du lli*/
  retour=libnet_close_link_interface(pspoof->plli);
  if ( retour == -1 )
  { return(LCRZO_ERR_FULIBNETCLOSELINKINT);
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#elif defined LCRZODEF_SYSTEM_Linux
int lcrzo_priv_spoof_init_eth(lcrzo_spoof *pspoof,
			        const lcrzo_device device)
{
  lcrzo_er(lcrzo_device_init(device, pspoof->device));
  
  /*ouverture de la socket*/ 
  pspoof->fd=socket(AF_INET, SOCK_PACKET, lcrzo_htons(ETH_P_ALL));
  if(pspoof->fd<0) return(LCRZO_ERR_FUSOCKET);

  return(LCRZO_ERR_OK);
}
int lcrzo_priv_spoof_eth(lcrzo_spoof *pspoof,
			 const lcrzo_device device, 
			 lcrzo_constdata packet, 
			 lcrzo_int32 nboctpacket)
{ int retour;
  struct sockaddr sa;
 
  /*uniquement pour faire plaisir a sendto (send() ne marche pas)*/
  memset(&sa, 0, sizeof(struct sockaddr));
  lcrzo_er(lcrzo_string_init_coretext(device, 
				      sizeof(sa.sa_data)-1, sa.sa_data));

  /*envoi*/
  retour=LAURENT_sendto(pspoof->fd, packet, nboctpacket, 0, &sa, sizeof(sa));
  if(retour<0) return(LCRZO_ERR_FUSENDTO);

  return(LCRZO_ERR_OK);
}
int lcrzo_priv_spoof_close_eth(lcrzo_spoof *pspoof)
{ int retour;
  
  retour=close(pspoof->fd);
  if(retour<0) return(LCRZO_ERR_FUCLOSE);

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#elif defined LCRZODEF_SYSTEM_FreeBSD || defined LCRZODEF_SYSTEM_OpenBSD
int lcrzo_priv_spoof_init_eth(lcrzo_spoof *pspoof,
			        const lcrzo_device device)
{ int i;
  char nombpf[12]; /*taille de /dev/bpfxxx*/

  /*on tente d'ouvrir tous les bpf definis*/
  for ( i=0; i<1000 ; i++)
  { lcrzo_string_init_text("/dev/bpf", 10, nombpf);
    lcrzo_string_append_int(i, "%d", 10, nombpf);
    pspoof->fd=open(nombpf, O_RDWR);
    if ( pspoof->fd==-1 )
    { if ( errno==EBUSY ) continue; /*erreur non grave*/
      return(LCRZO_ERR_FUOPEN); /*on est arrive a dernier : erreur*/
    }
    else
    { break; /*fd contient un descripteur valide*/
    }
  }

#if LCRZODEF_HAVEFONC_IOCTL_BIOCSHDRCMPLT==1
  /*on dit que bpf ne doit pas modifier les entetes ethernet*/
  { int retour;
    u_int un;
    un=1;
    retour=ioctl(pspoof->fd, BIOCSHDRCMPLT, (caddr_t)&un);
    if ( retour==-1 )
    { close(pspoof->fd);
      return(LCRZO_ERR_FUIOCTL);
    }
  }
#endif

  lcrzo_er(lcrzo_device_init(device, pspoof->device));
  return(LCRZO_ERR_OK);
}
int lcrzo_priv_spoof_eth(lcrzo_spoof *pspoof,
			 const lcrzo_device device, 
			 lcrzo_constdata packet, 
			 lcrzo_int32 nboctpacket)
{ int retour;
  struct ifreq ifr;

  /*on dit quelle interface va spoofer*/ 
  lcrzo_string_init_text(device, sizeof(ifr.ifr_name)-1, ifr.ifr_name);
  retour=ioctl(pspoof->fd, BIOCSETIF, (caddr_t)&ifr);
  if ( retour==-1 )
  { return(LCRZO_ERR_FUIOCTL);
  }

  /*on ecrit*/
  lcrzo_er(lcrzo_priv_fd_write(pspoof->fd, packet, nboctpacket));

  return(LCRZO_ERR_OK);
}
int lcrzo_priv_spoof_close_eth(lcrzo_spoof *pspoof)
{ int retour;
  
  retour=close(pspoof->fd);
  if(retour<0) return(LCRZO_ERR_FUCLOSE);

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#elif defined LCRZODEF_SYSTEM_Solaris
int lcrzo_priv_spoof_init_eth(lcrzo_spoof *pspoof,
			        const lcrzo_device device)
{ 
  lcrzo_er(lcrzo_device_init(device, pspoof->device));
  lcrzo_er(lcrzo_priv_dlpi_open(pspoof->device, &(pspoof->fd)));
  return(LCRZO_ERR_OK);
}
int lcrzo_priv_spoof_eth(lcrzo_spoof *pspoof,
			 const lcrzo_device device, 
			 lcrzo_constdata packet, 
			 lcrzo_int32 nboctpacket)
{ int retour;
  struct strbuf data;
  lcrzo_data paq;

  /* ecriture du packet */
  data.maxlen = nboctpacket;
  data.len    = nboctpacket;
  lcrzo_er(lcrzo_data_initm_data(packet, nboctpacket, &paq, NULL));
  data.buf   =(lcrzo_int8*)paq;
  retour = putmsg(pspoof->fd, NULL, &data, 0);
  lcrzo_data_free(paq);
  if ( retour < -1 )
  { return(LCRZO_ERR_FUPUTMSG);
  }

  return(LCRZO_ERR_OK);
  device=device;
}
int lcrzo_priv_spoof_close_eth(lcrzo_spoof *pspoof)
{ int retour;
  
  /* fermeture */
  retour=close(pspoof->fd);
  if (retour==-1) return(LCRZO_ERR_FUCLOSE);

  return(LCRZO_ERR_OK);
}
#elif defined LCRZODEF_SYSTEM_Windows
int lcrzo_priv_spoof_init_eth(lcrzo_spoof *pspoof,
			        const lcrzo_device device)
{ BOOL err;

  lcrzo_er(lcrzo_device_init(device, pspoof->device));
  /* open the adapter */
#if 0
  /* I don't think unicode is used anywhere. We should implement the function
     like this */
  { lcrzo_data unicodedev;
    lcrzo_er(lcrzo_priv_unicode_initm_device(pspoof->device, &unicodedev));
    pspoof->padapter = lcrzo_priv_cs_PacketOpenAdapter(unicodedev);
    lcrzo_data_free(unicodedev);
  }
#else
  { lcrzo_device dev;
    lcrzo_er(lcrzo_priv_ascii_init_device(pspoof->device, dev));
    pspoof->padapter = lcrzo_priv_cs_PacketOpenAdapter(dev);
  }
#endif

  if (pspoof->padapter==NULL) return(LCRZO_ERR_FUPACKETOPENADAPTER);
  err=PacketSetBuff(pspoof->padapter, 512000);
  if (!err) return(LCRZO_ERR_FUPACKETSETBUFF);

  return(LCRZO_ERR_OK);
}
int lcrzo_priv_spoof_eth(lcrzo_spoof *pspoof,
			 const lcrzo_device device, 
			 lcrzo_constdata packet, 
			 lcrzo_int32 nboctpacket)
{ LPPACKET lpPacket;
  lcrzo_data data;
  BOOL err;
  
  lpPacket = PacketAllocatePacket();
  if (lpPacket==NULL) return(LCRZO_ERR_FUPACKETALLOCATEPACKET);
  
  /* PacketInitPacket does not use const, so we must allocate */
  lcrzo_er(lcrzo_data_initm_data(packet, nboctpacket, &data, NULL));

  /*void*/PacketInitPacket(lpPacket, data, nboctpacket);

  /* send the packet */  
  err=PacketSendPacket(pspoof->padapter, lpPacket, TRUE);
  lcrzo_er(lcrzo_data_free(data)); /* cannot free before because PacketInitPacket do not allocate */ 
  if (!err) return(LCRZO_ERR_FUPACKETSENDPACKET);

  /*void*/PacketFreePacket(lpPacket);

  return(LCRZO_ERR_OK);
  /* just for the compiler warning */
  device=device;
}
int lcrzo_priv_spoof_close_eth(lcrzo_spoof *pspoof)
{ 
  /*void*/lcrzo_priv_cs_PacketCloseAdapter(pspoof->padapter);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif

