/*
** xipnet.c for  in 
** 
** Made by 
** Login   <vianney@epita.fr>
** 
** Started on  Wed Sep  1 08:26:59 1999 
** Last update Tue Nov 23 04:38:29 1999 
*/
#include "config.h"
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <net/bpf.h>
#include <libnet.h>
#include "pat_sz.h"
#include "pat_ether.h"
#include "pat_arp.h"
#include "xippkt.h"
#include "xipvar.h"
#include "xipnet.h"

t_assoc			dlt_assocs[] = 
{
  {"null",		(VOID_PTR)DLT_NULL},
  {"en10mb",		(VOID_PTR)DLT_EN10MB},
  {"en3mb",		(VOID_PTR)DLT_EN3MB},
  {"ax25",		(VOID_PTR)DLT_AX25},
  {"pronet",		(VOID_PTR)DLT_PRONET},
  {"chaos",		(VOID_PTR)DLT_CHAOS},
  {"ieee802",		(VOID_PTR)DLT_IEEE802},
  {"arcnet",		(VOID_PTR)DLT_ARCNET},
  {"slip",		(VOID_PTR)DLT_SLIP},
  {"ppp",		(VOID_PTR)DLT_PPP},
  {"fddi",		(VOID_PTR)DLT_FDDI},
  {"atm_rfc1483",	(VOID_PTR)DLT_ATM_RFC1483},
  {"raw",		(VOID_PTR)DLT_RAW},
  {"slip_bsdos",	(VOID_PTR)DLT_SLIP_BSDOS},
  {"ppp_bsdos",		(VOID_PTR)DLT_PPP_BSDOS},
  NULL_ASSOC
};

char			net_ifname[STR_BUFSIZ] = {0};
struct libnet_link_int	*libnet = NULL;

/* is a t_xip_method_proc.
   Sends out an ethernet packet.
   Returns 0 if OK. ERR_XIP_NO_METHOD if packet is not recognized.
   Might return various errors */
t_status			net_method_proc_send(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;

  if (!libnet)
    {
      fprintf(stderr, "missing net_if in configuration panel\n");
      return (ERR_XIP_NO_METHOD);
    }
  if (xmd->xp->pkt->pat == &ether_pat && libnet->linktype == DLT_EN10MB)
    {
      if (libnet_write_link_layer(libnet,
				  net_ifname,
				  xmd->xp->pkt->buf,
				  xmd->xp->pkt->len) < 0)
	return (ERR_XIP_WRITE);
      return (0);
    }
  return (ERR_XIP_NO_METHOD);
}

int	netifname_chan;

PAT_NAME_GENERIC(netifname_pat_name,
		 (VOID_PTR)&netifname_chan,
		 "netifname")

PAT_INSERT_DECL(netifname_pat_insert)
{
  t_status	status;
  char		errorbuf[STR_BUFSIZ];

  assert(sz_pat.insert_proc);
  if ((status = sz_pat.insert_proc(NULL,
				   buf,
				   len,
				   value)) != 0)
    return (status);
  if ((libnet = libnet_open_link_interface(net_ifname,
					   errorbuf)) == NULL)
    {
      err_print(ERR_XIP_OPEN,"interface `%s': %s",net_ifname,errorbuf);
      return (0);
    }
  return (0);
}

t_pat				netifname_pat = 
{
  netifname_pat_name,		/* t_pat_name_proc		*/
  NULL,				/* t_pat_off_proc		*/
  NULL,				/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  NULL,				/* t_pat_get_field_proc		*/
  NULL,				/* t_pat_set_field_proc		*/
  NULL,				/* t_pat_get_fields_proc	*/
  NULL,				/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  NULL,				/* t_pat_get_field_pat_proc	*/
  sz_pat_extract,		/* t_pat_extract_proc		*/
  netifname_pat_insert,		/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};

t_xip_var		net_vars[] = 
{
  {"net_ifname",
   (t_off)(&net_ifname),
   sizeof (net_ifname),
   &netifname_pat,
   NULL},
  NULL_XIP_VAR
};

t_xip_cf_box_entry	net_entries[] =
{
  {"netIfName",	"net_ifname"},
  NULL_XIP_CF_BOX_ENTRY
};

t_xip_cf_box_group	net_group = 
{"netGroup",	"net",	net_entries};

/* initializes alpha stuff.
   Note: registers a new packet bar title, a new method and new variables.
   Returns 0. If it is not able to open net_ifname (interface), it
   prints out an error message. */
t_status		xip_net_init(VOID_DECL)
{
  t_status		status;
  t_xip_method		xm;
  t_xip_pkt_bar		xpb;
  t_xip_var		*xv;
  
  xm.name = "send";
  xm.proc = net_method_proc_send;
  if ((status = xip_method_add(&xm)) != 0)
    return (status);
  xpb.label = "Send";
  xpb.methodstr = "send()";
  if ((status = xip_pkt_bar_add(&xpb)) != 0)
    return (status);
  xv = net_vars;
  while (xv->name)
    {
      if ((status = xip_var_add(xv)) != 0)
	return (status);
      xv++;
    }
  if ((status = xip_cf_box_group_add(&net_group)) != 0)
    return (status);
  return (0);
}
