/*
		                  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).

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

#include "lcrzo_incl.h"


/*-------------------------------------------------------------*/
typedef struct {
  lcrzo_bool priority;
  lcrzo_device device;
  lcrzo_etha eth;
  lcrzo_ipl ip;
  lcrzo_ipl netmask;
  lcrzo_uint32 mtu;
  lcrzo_bool isup;
  lcrzo_bool isanalias;
} lcrzo_priv_conf_devices;

typedef struct {
  lcrzo_bool priority;
  lcrzo_device device;
  lcrzo_etha eth;
  lcrzo_ipl ip;
  lcrzo_bool ispermanent;
  lcrzo_uint32 timeset;
} lcrzo_priv_conf_arp;

typedef struct {
  lcrzo_bool priority;
  lcrzo_device device;
  lcrzo_ipl dest;
  lcrzo_ipl mask;
  lcrzo_ipl ipsource;
  lcrzo_ipl gateway;
  lcrzo_uint32 metric;
  lcrzo_bool isup;
} lcrzo_priv_conf_routes;

typedef struct {
  lcrzo_uint32 number;
  lcrzo_device name;
} lcrzo_priv_conf_devicenumbername;

typedef struct {
  lcrzo_device device;
  lcrzo_etha eth;
} lcrzo_priv_conf_deviceeth;

#define LCRZO_PRIV_CONF_VALIDIPINFO_MAXGW 10
typedef struct {
  lcrzo_uint8 keyid[2];
  lcrzo_device device;
  lcrzo_etha eth;
  lcrzo_ipl ip;
  lcrzo_ipl mask;
  lcrzo_ipl gw[LCRZO_PRIV_CONF_VALIDIPINFO_MAXGW];
} lcrzo_priv_conf_validdhcpinfo;


/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_conf_packetgetadapternames.c"
#include "sysdep/lcrzo_priv_conf_device_init_devicealias.c"
#include "sysdep/lcrzo_priv_conf_etha_init_cardnumberdevice.c"
#include "sysdep/lcrzo_priv_conf_localeth.c"
#include "sysdep/lcrzo_priv_conf_localip.c"
#include "sysdep/lcrzo_priv_conf_validdhcpinfo.c"
#include "sysdep/lcrzo_priv_conf_device_init_ipl.c"
#include "sysdep/lcrzo_priv_conf_devicenumbername.c"
#include "sysdep/lcrzo_priv_conf_init_dev.c"
#include "sysdep/lcrzo_priv_conf_init_arpcache.c"
#include "sysdep/lcrzo_priv_conf_init_rarpcache.c"
#include "sysdep/lcrzo_priv_conf_init_routes.c"

/*-------------------------------------------------------------*/
int lcrzo_priv_confvars_init(lcrzo_priv_confvars *ptr)
{ 
  /* initialize the lists */
  lcrzo_er(lcrzo_list_init(&(ptr->list_system_devices),
			     sizeof(lcrzo_priv_conf_devices), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_system_arpperm),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_system_arpcache),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_system_routes),
			     sizeof(lcrzo_priv_conf_routes), NULL));

  lcrzo_er(lcrzo_list_init(&(ptr->list_systemdel_devices),
			     sizeof(lcrzo_priv_conf_devices), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_systemdel_arpperm),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_systemdel_arpcache),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_systemdel_routes),
			     sizeof(lcrzo_priv_conf_routes), NULL));

  lcrzo_er(lcrzo_list_init(&(ptr->list_user_devices),
			     sizeof(lcrzo_priv_conf_devices), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_user_arpperm),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_user_arpcache),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_user_routes),
			     sizeof(lcrzo_priv_conf_routes), NULL));

  lcrzo_er(lcrzo_list_init(&(ptr->list_sys_devices),
			     sizeof(lcrzo_priv_conf_devices), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_sys_arpperm),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_sys_arpcache),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_sys_routes),
			     sizeof(lcrzo_priv_conf_routes), NULL));

  lcrzo_er(lcrzo_list_init(&(ptr->list_conf_devices),
			     sizeof(lcrzo_priv_conf_devices), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_conf_arpperm),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_conf_arpcache),
			     sizeof(lcrzo_priv_conf_arp), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_conf_routes),
			     sizeof(lcrzo_priv_conf_routes), NULL));

  lcrzo_er(lcrzo_list_init(&(ptr->list_devicenumbername),
			     sizeof(lcrzo_priv_conf_devicenumbername), NULL));
  lcrzo_er(lcrzo_iplist_init(&(ptr->list_localip)));
  lcrzo_er(lcrzo_list_init(&(ptr->list_localeth),
			     sizeof(lcrzo_priv_conf_deviceeth), NULL));
  lcrzo_er(lcrzo_list_init(&(ptr->list_validdhcpinfo),
			     sizeof(lcrzo_priv_conf_validdhcpinfo), NULL));

  ptr->sysrenew_allow=LCRZO_TRUE;
  ptr->sysrenew_allow_devices=LCRZO_TRUE;
  ptr->sysrenew_allow_arpperm=LCRZO_TRUE;
  ptr->sysrenew_allow_arpcache=LCRZO_TRUE;
  ptr->sysrenew_allow_routes=LCRZO_TRUE;

  ptr->sysrenew_now=LCRZO_TRUE;
  ptr->sysrenew_now_devices=LCRZO_FALSE;
  ptr->sysrenew_now_arpperm=LCRZO_FALSE;
  ptr->sysrenew_now_arpcache=LCRZO_FALSE;
  ptr->sysrenew_now_routes=LCRZO_FALSE;

  ptr->compute_sys_devices=LCRZO_FALSE;
  ptr->compute_sys_arpperm=LCRZO_FALSE;
  ptr->compute_sys_arpcache=LCRZO_FALSE;
  ptr->compute_sys_routes=LCRZO_FALSE;
  ptr->compute_conf_devices=LCRZO_FALSE;
  ptr->compute_conf_arpperm=LCRZO_FALSE;
  ptr->compute_conf_arpcache=LCRZO_FALSE;
  ptr->compute_conf_routes=LCRZO_FALSE;

  ptr->cacheentriestimeout=120;

  ptr->permentriesperiod=60;
  ptr->permentrieslastupdatetime=0;

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_confvars_close(lcrzo_priv_confvars *ptr)
{ 
  lcrzo_er(lcrzo_list_close(&(ptr->list_system_devices)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_system_arpperm)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_system_arpcache)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_system_routes)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_systemdel_devices)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_systemdel_arpperm)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_systemdel_arpcache)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_systemdel_routes)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_sys_devices)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_sys_arpperm)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_sys_arpcache)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_sys_routes)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_user_devices)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_user_arpperm)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_user_arpcache)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_user_routes)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_conf_devices)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_conf_arpperm)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_conf_arpcache)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_conf_routes)));

  lcrzo_er(lcrzo_list_close(&(ptr->list_devicenumbername)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_localeth)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_localip)));
  lcrzo_er(lcrzo_list_close(&(ptr->list_validdhcpinfo)));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_confvars_ptr_get(lcrzo_priv_confvars **pptr)
{ lcrzo_priv_globalvars *ptrglo;

  lcrzo_er(lcrzo_priv_globalvars_ptr_get(&ptrglo));
    
  if (pptr!=NULL)
  { *pptr=&(ptrglo->confvars);
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_list_copy(lcrzo_list *psrc, lcrzo_list *pdst);
int lcrzo_priv_conf_list_copy(lcrzo_list *psrc, lcrzo_list *pdst)
{ lcrzo_int32 count, i;
  union {
  lcrzo_priv_conf_devices cd;
  lcrzo_priv_conf_arp ca;
  lcrzo_priv_conf_routes cr;
  lcrzo_priv_conf_devicenumbername dnn;
  lcrzo_priv_conf_deviceeth de;
  lcrzo_iplist il;
  lcrzo_priv_conf_validdhcpinfo vdi;
  } item, *pitem;
  pitem=&item;

  /* copy all items from src */
  lcrzo_er(lcrzo_list_count(psrc, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(psrc, i, pitem));
    lcrzo_er(lcrzo_list_add_last(pdst, pitem));
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_confvars_copy(lcrzo_priv_confvars *srcptr,
                             lcrzo_priv_confvars *dstptr)
{
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_system_devices, &dstptr->list_system_devices));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_system_arpperm, &dstptr->list_system_arpperm));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_system_arpcache, &dstptr->list_system_arpcache));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_system_routes, &dstptr->list_system_routes));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_systemdel_devices, &dstptr->list_systemdel_devices));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_systemdel_arpperm, &dstptr->list_systemdel_arpperm));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_systemdel_arpcache, &dstptr->list_systemdel_arpcache));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_systemdel_routes, &dstptr->list_systemdel_routes));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_user_devices, &dstptr->list_user_devices));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_user_arpperm, &dstptr->list_user_arpperm));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_user_arpcache, &dstptr->list_user_arpcache));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_user_routes, &dstptr->list_user_routes));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_sys_devices, &dstptr->list_sys_devices));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_sys_arpperm, &dstptr->list_sys_arpperm));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_sys_arpcache, &dstptr->list_sys_arpcache));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_sys_routes, &dstptr->list_sys_routes));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_conf_devices, &dstptr->list_conf_devices));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_conf_arpperm, &dstptr->list_conf_arpperm));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_conf_arpcache, &dstptr->list_conf_arpcache));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_conf_routes, &dstptr->list_conf_routes));

  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_devicenumbername, &dstptr->list_devicenumbername));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_localeth, &dstptr->list_localeth));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_localip, &dstptr->list_localip));
  lcrzo_er(lcrzo_priv_conf_list_copy(&srcptr->list_localip, &dstptr->list_validdhcpinfo));
 
  dstptr->sysrenew_allow=srcptr->sysrenew_allow;
  dstptr->sysrenew_allow_devices=srcptr->sysrenew_allow_devices;
  dstptr->sysrenew_allow_arpperm=srcptr->sysrenew_allow_arpperm;
  dstptr->sysrenew_allow_arpcache=srcptr->sysrenew_allow_arpcache;
  dstptr->sysrenew_allow_routes=srcptr->sysrenew_allow_routes;
  dstptr->sysrenew_now=srcptr->sysrenew_now;
  dstptr->sysrenew_now_devices=srcptr->sysrenew_now_devices;
  dstptr->sysrenew_now_arpperm=srcptr->sysrenew_now_arpperm;
  dstptr->sysrenew_now_arpcache=srcptr->sysrenew_now_arpcache;
  dstptr->sysrenew_now_routes=srcptr->sysrenew_now_routes;

  dstptr->compute_sys_devices=srcptr->compute_sys_devices;
  dstptr->compute_sys_arpperm=srcptr->compute_sys_arpperm;
  dstptr->compute_sys_arpcache=srcptr->compute_sys_arpcache;
  dstptr->compute_sys_routes=srcptr->compute_sys_routes;
  dstptr->compute_conf_devices=srcptr->compute_conf_devices;
  dstptr->compute_conf_arpperm=srcptr->compute_conf_arpperm;
  dstptr->compute_conf_arpcache=srcptr->compute_conf_arpcache;
  dstptr->compute_conf_routes=srcptr->compute_conf_routes;

  dstptr->cacheentriestimeout=srcptr->cacheentriestimeout;
  dstptr->permentriesperiod=srcptr->permentriesperiod;
  dstptr->permentrieslastupdatetime=srcptr->permentrieslastupdatetime;

  return(LCRZO_ERR_OK);
}


/*-------------------------------------------------------------*/
lcrzo_bool lcrzo_priv_conf_devices_cmp(const void *pelem, void *pinfos);
lcrzo_bool lcrzo_priv_conf_devices_cmp(const void *pelem, void *pinfos)
{ const lcrzo_priv_conf_devices de1=*(const lcrzo_priv_conf_devices *)pelem;
  lcrzo_priv_conf_devices de2=*(lcrzo_priv_conf_devices *)pinfos;

  if ( lcrzo_device_equal(de1.device, de2.device) &&
       lcrzo_etha_equal(de1.eth, de2.eth) &&
       lcrzo_ipl_equal(de1.ip, de2.ip) )
  { return(LCRZO_TRUE);
  }
  return(LCRZO_FALSE);
}

lcrzo_bool lcrzo_priv_conf_arp_cmp(const void *pelem, void *pinfos);
lcrzo_bool lcrzo_priv_conf_arp_cmp(const void *pelem, void *pinfos)
{ const lcrzo_priv_conf_arp de1=*(const lcrzo_priv_conf_arp *)pelem;
  lcrzo_priv_conf_arp de2=*(lcrzo_priv_conf_arp *)pinfos;

  if ( lcrzo_device_equal(de1.device, de2.device) &&
       lcrzo_etha_equal(de1.eth, de2.eth) &&
       lcrzo_ipl_equal(de1.ip, de2.ip) )
  { return(LCRZO_TRUE);
  }
  return(LCRZO_FALSE);
}
lcrzo_bool lcrzo_priv_conf_arp_cmpwdev(const void *pelem, void *pinfos);
lcrzo_bool lcrzo_priv_conf_arp_cmpwdev(const void *pelem, void *pinfos)
{ const lcrzo_priv_conf_arp de1=*(const lcrzo_priv_conf_arp *)pelem;
  lcrzo_priv_conf_arp de2=*(lcrzo_priv_conf_arp *)pinfos;

  if ( lcrzo_etha_equal(de1.eth, de2.eth) &&
       lcrzo_ipl_equal(de1.ip, de2.ip) )
  { return(LCRZO_TRUE);
  }
  return(LCRZO_FALSE);
}
lcrzo_bool lcrzo_priv_conf_arp_purge(const void *pelem, void *pinfos);
lcrzo_bool lcrzo_priv_conf_arp_purge(const void *pelem, void *pinfos)
{ const lcrzo_priv_conf_arp de=*(const lcrzo_priv_conf_arp *)pelem;
  lcrzo_uint32 purgeolderthan=*(lcrzo_uint32 *)pinfos;

  if ( de.timeset<purgeolderthan )
  { return(LCRZO_TRUE);
  }
  return(LCRZO_FALSE);
}

lcrzo_bool lcrzo_priv_conf_routes_cmp(const void *pelem, void *pinfos);
lcrzo_bool lcrzo_priv_conf_routes_cmp(const void *pelem, void *pinfos)
{ const lcrzo_priv_conf_routes de1=*(const lcrzo_priv_conf_routes *)pelem;
  lcrzo_priv_conf_routes de2=*(lcrzo_priv_conf_routes *)pinfos;

  if ( lcrzo_ipl_equal(de1.dest, de2.dest) &&
       lcrzo_ipl_equal(de1.mask, de2.mask) &&
       lcrzo_ipl_equal(de1.gateway, de2.gateway) )
  { return(LCRZO_TRUE);
  }
  return(LCRZO_FALSE);
}

lcrzo_int8 lcrzo_priv_conf_routes_sortcmp(const void *peleminf,
				   const void *pelemsup,
				   void *pinfos);
lcrzo_int8 lcrzo_priv_conf_routes_sortcmp(const void *peleminf,
				   const void *pelemsup,
				   void *pinfos)
{ const lcrzo_priv_conf_routes de1=*(const lcrzo_priv_conf_routes *)peleminf;
  const lcrzo_priv_conf_routes de2=*(const lcrzo_priv_conf_routes *)pelemsup;
  lcrzo_uint32 net1, net2;

  net1= ~de1.mask;
  net2= ~de2.mask;

  if ( net1==net2 )
  { if (de1.dest==de2.dest) 
    { if (de1.metric==de2.metric) return(0);
      else if (de1.metric<de2.metric) return(-1);
      else return(+1);
    }
    else
      return(0);
  }
  else if ( net1>net2 ) return(+1);
  else return(-1);
  pinfos=pinfos; /*just for the compiler*/
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_conf_system_renew.c"

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_sys_renew(lcrzo_list *plist_system,
                              lcrzo_list *plist_systemdel,
                              lcrzo_list *plist_sys,
                              lcrzo_bool (*pfunc_cmp)(const void *pelem, void *pinfos));
int lcrzo_priv_conf_sys_renew(lcrzo_list *plist_system,
                              lcrzo_list *plist_systemdel,
                              lcrzo_list *plist_sys,
                              lcrzo_bool (*pfunc_cmp)(const void *pelem, void *pinfos))
{ lcrzo_int32 count, i;
  lcrzo_priv_conf_devices cd;
  lcrzo_priv_conf_arp ca;
  lcrzo_priv_conf_routes cr;
  void *pitem;

  /* select which item to use */
  if ( pfunc_cmp==&lcrzo_priv_conf_devices_cmp) pitem=&cd;
  else if ( pfunc_cmp==&lcrzo_priv_conf_arp_cmp) pitem=&ca;
  else if ( pfunc_cmp==&lcrzo_priv_conf_routes_cmp) pitem=&cr;
  else
  { return(lcrzo_ie("lcrzo_priv_conf_compute", 
                    "mauvaise adresse pour pfunc_cmp",
                    "bad address for pfunc_cmp"));
  }

  /* remove items in sys */
  lcrzo_er(lcrzo_list_remove_all(plist_sys));

  /* copy all items from system */
  lcrzo_er(lcrzo_list_count(plist_system, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist_system, i, pitem));
    lcrzo_er(lcrzo_list_add_last(plist_sys, pitem));
  }

  /* remove all items from systemdel */
  lcrzo_er(lcrzo_list_count(plist_systemdel, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist_systemdel, i, pitem));
    lcrzo_er(lcrzo_list_remove_criteria_all(plist_sys, pfunc_cmp, pitem));
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_conf_renew(lcrzo_list *plist_sys,
                               lcrzo_list *plist_user,
                               lcrzo_list *plist_conf,
                               lcrzo_bool (*pfunc_cmp)(const void *pelem, void *pinfos));
int lcrzo_priv_conf_conf_renew(lcrzo_list *plist_sys,
                               lcrzo_list *plist_user,
                               lcrzo_list *plist_conf,
                               lcrzo_bool (*pfunc_cmp)(const void *pelem, void *pinfos))
{ lcrzo_int32 count, i, pos;
  lcrzo_priv_conf_devices cd;
  lcrzo_priv_conf_arp ca;
  lcrzo_priv_conf_routes cr;
  void *pitem;
  int ret;

  /* select which item to use */
  if ( pfunc_cmp==&lcrzo_priv_conf_devices_cmp) pitem=&cd;
  else if ( pfunc_cmp==&lcrzo_priv_conf_arp_cmp) pitem=&ca;
  else if ( pfunc_cmp==&lcrzo_priv_conf_routes_cmp) pitem=&cr;
  else
  { return(lcrzo_ie("lcrzo_priv_conf_compute", 
                    "mauvaise adresse pour pfunc_cmp",
                    "bad address for pfunc_cmp"));
  }

  /* remove items in conf */
  lcrzo_er(lcrzo_list_remove_all(plist_conf));

  /* put low priority user items */
  lcrzo_er(lcrzo_list_count(plist_user, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist_user, i, pitem));
    if (((lcrzo_priv_conf_devices*)pitem)->priority) continue;
    lcrzo_er(lcrzo_list_add_last(plist_conf, pitem));
  }

  /* update with sys items */
  lcrzo_er(lcrzo_list_count(plist_sys, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist_sys, i, pitem));
    /* search it in the list */
    ret=lcrzo_list_search_all(plist_conf, pfunc_cmp, pitem, &pos, NULL);
    if ( ret!=LCRZO_ERR_OKSEARCHNOTFOUND && ret!=LCRZO_ERR_OK )
      return(ret);
    if ( ret==LCRZO_ERR_OK )
    { /* we found it, so we replace it */
      lcrzo_er(lcrzo_list_replace_pos(plist_conf, pos, pitem));
    }
    else
    { /* we add it to the list */
      lcrzo_er(lcrzo_list_add_last(plist_conf, pitem));
    }
  }

  /* update with high priority user items */
  lcrzo_er(lcrzo_list_count(plist_user, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist_user, i, pitem));
    if ( ! ((lcrzo_priv_conf_devices*)pitem)->priority ) continue;
    /* search it in the list */
    ret=lcrzo_list_search_all(plist_conf, pfunc_cmp, pitem, &pos, NULL);
    if ( ret!=LCRZO_ERR_OKSEARCHNOTFOUND && ret!=LCRZO_ERR_OK )
      return(ret);
    if ( ret==LCRZO_ERR_OK )
    { /* we found it, so we replace it */
      lcrzo_er(lcrzo_list_replace_pos(plist_conf, pos, pitem));
    }
    else
    { /* we add it to the list */
      lcrzo_er(lcrzo_list_add_last(plist_conf, pitem));
    }
  }
  
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_confvar_print(lcrzo_conststring msg,
			     lcrzo_priv_confvars *ptr);
int lcrzo_priv_confvar_print(lcrzo_conststring msg,
			     lcrzo_priv_confvars *ptr)
{
  puts(msg);
  printf("sysrenew_allow %d dev=%d arpperm=%d arpcache=%d routes=%d\n",
	 ptr->sysrenew_allow, ptr->sysrenew_allow_devices,
	 ptr->sysrenew_allow_arpperm, ptr->sysrenew_allow_arpcache,
	 ptr->sysrenew_allow_routes);
  printf("sysrenew_now %d dev=%d arpperm=%d arpcache=%d routes=%d\n",
	 ptr->sysrenew_now, ptr->sysrenew_now_devices,
	 ptr->sysrenew_now_arpperm, ptr->sysrenew_now_arpcache,
	 ptr->sysrenew_now_routes);
  printf("compute_sys dev=%d arpperm=%d arpcache=%d routes=%d\n",
	 ptr->compute_sys_devices, ptr->compute_sys_arpperm,
	 ptr->compute_sys_arpcache, ptr->compute_sys_routes);
  printf("compute_conf dev=%d arpperm=%d arpcache=%d routes=%d\n",
	 ptr->compute_conf_devices, ptr->compute_conf_arpperm,
	 ptr->compute_conf_arpcache, ptr->compute_conf_routes);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_eventuallyupdate(lcrzo_priv_confvars *ptr);
int lcrzo_priv_conf_eventuallyupdate(lcrzo_priv_confvars *ptr)
{ lcrzo_time currenttime;
  lcrzo_uint32 removeolderthan, currenttimesec;
  lcrzo_bool system_renew;

  /*lcrzo_er(lcrzo_priv_confvar_print("Step 1", ptr));*/
  /* check if we have to update system entries */
  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_get_sec(&currenttime, &currenttimesec));
  system_renew=LCRZO_FALSE;
  if ( ptr->sysrenew_allow )
  { if ( ptr->sysrenew_now ||
         ptr->permentriesperiod == 0 ||
         ptr->permentriesperiod+ptr->permentrieslastupdatetime < currenttimesec )
    { if (ptr->sysrenew_allow_devices) ptr->compute_sys_devices=LCRZO_TRUE;
      if (ptr->sysrenew_allow_arpperm) ptr->compute_sys_arpperm=LCRZO_TRUE;
      if (ptr->sysrenew_allow_arpcache) ptr->compute_sys_arpcache=LCRZO_TRUE;
      if (ptr->sysrenew_allow_routes) ptr->compute_sys_routes=LCRZO_TRUE;
      system_renew=LCRZO_TRUE;
      /* unset for next call */
      ptr->sysrenew_now=LCRZO_FALSE; 
    }
    if ( ptr->sysrenew_now_devices && ptr->sysrenew_allow_devices )
    { ptr->compute_sys_devices=LCRZO_TRUE;
      system_renew=LCRZO_TRUE;
      /* unset for next call */
      ptr->sysrenew_now_devices=LCRZO_FALSE; 
    }
    if ( ptr->sysrenew_now_arpperm && ptr->sysrenew_allow_arpperm )
    { ptr->compute_sys_arpperm=LCRZO_TRUE;
      system_renew=LCRZO_TRUE;
      /* unset for next call */
      ptr->sysrenew_now_arpperm=LCRZO_FALSE; 
    }
    if ( ptr->sysrenew_now_arpcache && ptr->sysrenew_allow_arpcache )
    { ptr->compute_sys_arpcache=LCRZO_TRUE;
      system_renew=LCRZO_TRUE;
      /* unset for next call */
      ptr->sysrenew_now_arpcache=LCRZO_FALSE; 
    }
    if ( ptr->sysrenew_now_routes && ptr->sysrenew_allow_routes )
    { ptr->compute_sys_routes=LCRZO_TRUE;
      system_renew=LCRZO_TRUE;
      /* unset for next call */
      ptr->sysrenew_now_routes=LCRZO_FALSE; 
    }
  }

  /* update system entries */
  /*lcrzo_er(lcrzo_priv_confvar_print("Step 2", ptr));*/
  if ( system_renew )
  { lcrzo_er(lcrzo_priv_conf_system_renew(ptr));
    ptr->permentrieslastupdatetime=currenttimesec;
  }

  /* recompute new sys entries */
  /*lcrzo_er(lcrzo_priv_confvar_print("Step 3", ptr));*/
  if ( ptr->compute_sys_devices && 
       ptr->sysrenew_allow && ptr->sysrenew_allow_devices )
  { lcrzo_er(lcrzo_priv_conf_sys_renew(&ptr->list_system_devices,
                                       &ptr->list_systemdel_devices,
                                       &ptr->list_sys_devices,
                                       &lcrzo_priv_conf_devices_cmp));
    ptr->compute_conf_devices=LCRZO_TRUE;
    /* unset for next call */
    ptr->compute_sys_devices=LCRZO_FALSE; 
  }
  if ( ptr->compute_sys_arpperm && 
       ptr->sysrenew_allow && ptr->sysrenew_allow_arpperm )
  { lcrzo_er(lcrzo_priv_conf_sys_renew(&ptr->list_system_arpperm,
                                       &ptr->list_systemdel_arpperm,
                                       &ptr->list_sys_arpperm,
                                       &lcrzo_priv_conf_arp_cmp));
    ptr->compute_conf_arpperm=LCRZO_TRUE;
    /* unset for next call */
    ptr->compute_sys_arpperm=LCRZO_FALSE; 
  }
  if ( ptr->compute_sys_arpcache && 
       ptr->sysrenew_allow && ptr->sysrenew_allow_arpcache )
  { lcrzo_er(lcrzo_priv_conf_sys_renew(&ptr->list_system_arpcache,
                                       &ptr->list_systemdel_arpcache,
                                       &ptr->list_sys_arpcache,
                                       &lcrzo_priv_conf_arp_cmp));
    ptr->compute_conf_arpcache=LCRZO_TRUE;
    /* unset for next call */
    ptr->compute_sys_arpcache=LCRZO_FALSE; 
  }
  if ( ptr->compute_sys_routes && 
       ptr->sysrenew_allow && ptr->sysrenew_allow_routes )
  { lcrzo_er(lcrzo_priv_conf_sys_renew(&ptr->list_system_routes,
                                       &ptr->list_systemdel_routes,
                                       &ptr->list_sys_routes,
                                       &lcrzo_priv_conf_routes_cmp));
    ptr->compute_conf_routes=LCRZO_TRUE;
    /* unset for next call */
    ptr->compute_sys_routes=LCRZO_FALSE; 
  }

  /* recompute new conf items */
  /*lcrzo_er(lcrzo_priv_confvar_print("Step 4", ptr));*/
  if ( ptr->compute_conf_devices )
  { lcrzo_er(lcrzo_priv_conf_conf_renew(&ptr->list_sys_devices,
                                        &ptr->list_user_devices,
                                        &ptr->list_conf_devices,
                                        &lcrzo_priv_conf_devices_cmp));
    /* this is done */
    ptr->compute_conf_devices=LCRZO_FALSE;
  }
  if ( ptr->compute_conf_arpperm )
  { lcrzo_er(lcrzo_priv_conf_conf_renew(&ptr->list_sys_arpperm,
                                        &ptr->list_user_arpperm,
                                        &ptr->list_conf_arpperm,
                                        &lcrzo_priv_conf_arp_cmp));
    /* this is done */
    ptr->compute_conf_arpperm=LCRZO_FALSE;
  }
  if ( ptr->compute_conf_arpcache )
  { lcrzo_er(lcrzo_priv_conf_conf_renew(&ptr->list_sys_arpcache,
                                        &ptr->list_user_arpcache,
                                        &ptr->list_conf_arpcache,
                                        &lcrzo_priv_conf_arp_cmp));
    /* this is done */
    ptr->compute_conf_arpcache=LCRZO_FALSE;
  }
  if ( ptr->compute_conf_routes )
  { lcrzo_er(lcrzo_priv_conf_conf_renew(&ptr->list_sys_routes,
                                        &ptr->list_user_routes,
                                        &ptr->list_conf_routes,
                                        &lcrzo_priv_conf_routes_cmp));
    /* this is done */
    ptr->compute_conf_routes=LCRZO_FALSE;
  }

  /* remove old cache entries */
  if ( ptr->cacheentriestimeout )
  { removeolderthan=currenttimesec-ptr->cacheentriestimeout;
    lcrzo_er(lcrzo_list_remove_criteria_all(&ptr->list_conf_arpcache, 
					    &lcrzo_priv_conf_arp_purge,
					    &removeolderthan));
  }
  
  /*lcrzo_er(lcrzo_priv_confvar_print("Step 5", ptr));*/
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
int lcrzo_conf_fprint(LCRZOFILE *pf)
{ lcrzo_priv_confvars *ptr;
  lcrzo_bool sysrenew_allow_old;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptr));
  sysrenew_allow_old=ptr->sysrenew_allow;
  ptr->sysrenew_allow=LCRZO_FALSE;
  fprintf(pf, "Devices\n");
  lcrzo_er(lcrzo_conf_devices_fprint(pf));
  fprintf(pf, "Arp\n");
  lcrzo_er(lcrzo_conf_arp_fprint(pf));
  fprintf(pf, "Routes\n");
  lcrzo_er(lcrzo_conf_routes_fprint(pf));
  ptr->sysrenew_allow=sysrenew_allow_old;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_devices_add_system(const lcrzo_device device,
			          const lcrzo_etha etha,
			          lcrzo_ipl ipl,
			          lcrzo_ipl netmask,
			          lcrzo_uint32 mtu,
			          lcrzo_bool isup,
			          lcrzo_bool isanalias)
{ lcrzo_priv_conf_devices cd;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_int32 pos;
  int ret;
 
  /* ignore nul IP addresses */
  if (ipl==0) return(LCRZO_ERR_OK);

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
    
  /* initialize the structure */
  lcrzo_er(lcrzo_device_init(device, cd.device));
  cd.priority=LCRZO_FALSE;
  memcpy(cd.eth, etha, LCRZO_ETHA_MAXBYTES);
  cd.ip=ipl;
  cd.netmask=netmask;
  cd.mtu=mtu;
  cd.isup=isup;
  cd.isanalias=isanalias;

  /* search it in the list */
  ret=lcrzo_list_search_all(&ptrcv->list_system_devices,
			    &lcrzo_priv_conf_devices_cmp,
			    &cd, &pos, NULL);
  if ( ret!=LCRZO_ERR_OKSEARCHNOTFOUND && ret!=LCRZO_ERR_OK )
    return(ret);

  if ( ret==LCRZO_ERR_OK )
  { /* we found it, so we replace it */
    lcrzo_er(lcrzo_list_replace_pos(&ptrcv->list_system_devices, pos, &cd));
  }
  else
  { /* we add it to the list */
    lcrzo_er(lcrzo_list_add_last(&ptrcv->list_system_devices, &cd));
  }
  /* add it in the ARP cache */
  lcrzo_er(lcrzo_priv_conf_arp_add_system(device, etha, ipl, LCRZO_TRUE));
  /* add it in the routing table */
  lcrzo_er(lcrzo_priv_conf_routes_add_system(device, ipl, 0xFFFFFFFFu, 0, 0, 0, isup));
  lcrzo_er(lcrzo_priv_conf_routes_add_system(device, ipl&netmask, netmask, ipl, 0, 0, isup));
  
  ptrcv->compute_sys_devices=LCRZO_TRUE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_devices_add_user(lcrzo_bool priorityoversystem,
                                const lcrzo_device device,
			        const lcrzo_etha etha,
			        lcrzo_ipl ipl,
			        lcrzo_ipl netmask,
			        lcrzo_uint32 mtu,
			        lcrzo_bool isup,
			        lcrzo_bool isanalias)
{ lcrzo_priv_conf_devices cd;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_int32 pos;
  int ret;
 
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
    
  /* initialize the structure */
  lcrzo_er(lcrzo_device_init(device, cd.device));
  cd.priority=priorityoversystem;
  memcpy(cd.eth, etha, LCRZO_ETHA_MAXBYTES);
  cd.ip=ipl;
  cd.netmask=netmask;
  cd.mtu=mtu;
  cd.isup=isup;
  cd.isanalias=isanalias;

  /* search it in the list */
  ret=lcrzo_list_search_all(&ptrcv->list_user_devices,
			    &lcrzo_priv_conf_devices_cmp,
			    &cd, &pos, NULL);
  if ( ret!=LCRZO_ERR_OKSEARCHNOTFOUND && ret!=LCRZO_ERR_OK )
    return(ret);

  if ( ret==LCRZO_ERR_OK )
  { /* we found it, so we replace it */
    lcrzo_er(lcrzo_list_replace_pos(&ptrcv->list_user_devices, pos, &cd));
  }
  else
  { /* we add it to the list */
    lcrzo_er(lcrzo_list_add_last(&ptrcv->list_user_devices, &cd));
  }
  
  ptrcv->compute_conf_devices=LCRZO_TRUE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_devices_del_system(const lcrzo_device device,
			          const lcrzo_etha etha,
			          lcrzo_ipl ipl)
{ lcrzo_priv_conf_devices cd;
  lcrzo_priv_confvars *ptrcv;
 
  /* initialize the structure */
  cd.priority=LCRZO_FALSE;
  lcrzo_er(lcrzo_string_init_coretext(device, LCRZO_DEVICE_MAXBYTES, 
				      cd.device));
  memcpy(cd.eth, etha, LCRZO_ETHA_MAXBYTES);
  cd.ip=ipl;

  /* remove it from the list */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_add_last(&ptrcv->list_systemdel_devices, &cd));

  ptrcv->compute_sys_devices=LCRZO_TRUE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_devices_del_user(const lcrzo_device device,
			        const lcrzo_etha etha,
			        lcrzo_ipl ipl)
{ lcrzo_priv_conf_devices cd;
  lcrzo_priv_confvars *ptrcv;
 
  /* initialize the structure */
  cd.priority=LCRZO_FALSE;
  lcrzo_er(lcrzo_string_init_coretext(device, LCRZO_DEVICE_MAXBYTES, 
				      cd.device));
  memcpy(cd.eth, etha, LCRZO_ETHA_MAXBYTES);
  cd.ip=ipl;

  /* remove it from the list */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_criteria_all(&ptrcv->list_user_devices, 
					  &lcrzo_priv_conf_devices_cmp,
					  &cd));
  ptrcv->compute_conf_devices=LCRZO_TRUE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_devices_count(lcrzo_int32 *pcount)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));

  lcrzo_er(lcrzo_list_count(&ptrcv->list_conf_devices, pcount));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_devices_value_pos(lcrzo_int32 pos,
				 lcrzo_device device,
				 lcrzo_etha etha,
				 lcrzo_ipl *pipl,
				 lcrzo_ipl *pnetmask,
				 lcrzo_uint32 *pmtu,
				 lcrzo_bool *pisup,
				 lcrzo_bool *pisanalias)
{ lcrzo_priv_conf_devices cd;
  lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_value_pos(&ptrcv->list_conf_devices, pos, &cd));
  lcrzo_er(lcrzo_device_init(cd.device, device));
  if ( etha!=NULL ) memcpy(etha, cd.eth, LCRZO_ETHA_MAXBYTES);
  if ( pipl!=NULL ) *pipl=cd.ip;
  if ( pnetmask!=NULL ) *pnetmask=cd.netmask;
  if ( pmtu!=NULL ) *pmtu=cd.mtu;
  if ( pisup!=NULL ) *pisup=cd.isup;
  if ( pisanalias!=NULL ) *pisanalias=cd.isanalias;

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_fprint_cstsized(LCRZOFILE *pf, 
			       const char *string, lcrzo_int32 size);
int lcrzo_priv_fprint_cstsized(LCRZOFILE *pf, 
			       const char *string, lcrzo_int32 size)
{ int spacenumber, i;

  fprintf(pf, "%s", string);
  spacenumber=size-strlen(string);
  for ( i=0 ; i<spacenumber ; i++ )
  { fputc(' ', pf);
  }
  return(LCRZO_ERR_OK);
}

int lcrzo_conf_devices_fprint(LCRZOFILE *pf)
{ lcrzo_int32 count, i, strlen_device;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_priv_conf_devices cd;
  lcrzo_ips ips;
  lcrzo_int16 language;
  char c;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));

  lcrzo_er(lcrzo_list_count(&ptrcv->list_conf_devices, &count));
  if (count)
  { lcrzo_er(lcrzo_global_get_language(&language));
    if (language==LCRZO_GLOBAL_LANG_FR )
    { fprintf(pf, "  device  ethernet          ip             /netmask");
      fprintf(pf, "          mtu\n");
    }
    else
    { fprintf(pf, "  device  ethernet          ip             /netmask");
      fprintf(pf, "          mtu\n");
    }
  }
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(&ptrcv->list_conf_devices, i, &cd));
    strlen_device=strlen(cd.device);
    if (strlen_device>7)
    { c=cd.device[strlen_device-7];
      cd.device[strlen_device-7]='\0';
      fprintf(pf, "  %s...\n", cd.device);
      cd.device[strlen_device-7]=c;
      fprintf(pf, "  ");
      lcrzo_priv_fprint_cstsized(pf, cd.device+strlen_device-7, 8);
    }
    else
    { fprintf(pf, "  ");
      lcrzo_priv_fprint_cstsized(pf, cd.device, 8);
    }
    lcrzo_er(lcrzo_etha_fprint(pf, "", cd.eth, " "));
    lcrzo_er(lcrzo_ips_init_ipl(cd.ip, ips));
    lcrzo_priv_fprint_cstsized(pf, ips, 15);
    fprintf(pf, "/");
    lcrzo_er(lcrzo_ips_init_ipl(cd.netmask, ips));
    lcrzo_priv_fprint_cstsized(pf, ips, 16);
    lcrzo_uint32_fprint(pf, "", cd.mtu, "%5u", " ");
    if (cd.isup)
      fprintf(pf, "up");
    else
      fprintf(pf, "down");
    if (cd.isanalias)
      fprintf(pf, ",alias");
    fprintf(pf, "\n");
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_arp_add_system(const lcrzo_device device,
				   const lcrzo_etha etha,
				   lcrzo_ipl ipl,
				   lcrzo_bool ispermanent)
{ lcrzo_priv_conf_arp ca, permfoundca, cachefoundca;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_time currenttime;
  lcrzo_int32 permpos, cachepos;
  int permret, cacheret;

  /* if theses case, we do not add it */
  if (!ispermanent)
  { if ( ipl==0 ) return(LCRZO_ERR_OK);
    if ( ipl==0xFFFFFFFFu ) return(LCRZO_ERR_OK);
    if ( etha[0]==0 && etha[1]==0 && etha[2]==0 && 
	 etha[3]==0 && etha[4]==0 && etha[5]==0 )
      return(LCRZO_ERR_OK);
    if ( etha[0]==0xFF && etha[1]==0xFF && etha[2]==0xFF && 
	 etha[3]==0xFF && etha[4]==0xFF && etha[5]==0xFF )
      return(LCRZO_ERR_OK);
  }

  /* initialize the structure */
  ca.priority=LCRZO_FALSE;
  memcpy(ca.eth, etha, LCRZO_ETHA_MAXBYTES);
  lcrzo_er(lcrzo_device_init(device, ca.device));
  ca.ip=ipl;
  ca.ispermanent=ispermanent;
  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_get_sec(&currenttime, &(ca.timeset)));

  /* search it in the lists */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  permret=lcrzo_list_search_all(&ptrcv->list_system_arpperm,
				&lcrzo_priv_conf_arp_cmpwdev,
				&ca, &permpos, &permfoundca);
  if ( permret!=LCRZO_ERR_OKSEARCHNOTFOUND && permret!=LCRZO_ERR_OK )
    return(permret);
  cacheret=lcrzo_list_search_all(&ptrcv->list_system_arpcache,
				 &lcrzo_priv_conf_arp_cmpwdev,
				 &ca, &cachepos, &cachefoundca);
  if ( cacheret!=LCRZO_ERR_OKSEARCHNOTFOUND && cacheret!=LCRZO_ERR_OK )
    return(cacheret);

  /* if the user doesn't know the device, we look if we already know it */
  if ( strlen(ca.device)==0 )
  { if ( permret==LCRZO_ERR_OK && strlen(permfoundca.device)!=0 )
    { lcrzo_er(lcrzo_device_init(permfoundca.device, ca.device));
    }
    else if ( cacheret==LCRZO_ERR_OK && strlen(cachefoundca.device)!=0 )
    { lcrzo_er(lcrzo_device_init(cachefoundca.device, ca.device));
    }
  }

  if ( ispermanent )
  { ptrcv->compute_sys_arpperm=LCRZO_TRUE;
    if ( permret==LCRZO_ERR_OK ) 
    { /* we found it, so we replace it */
      lcrzo_er(lcrzo_list_replace_pos(&ptrcv->list_system_arpperm, 
				      permpos, &ca));
    }
    else
    { /* we add it to the list */
      lcrzo_er(lcrzo_list_add_last(&ptrcv->list_system_arpperm, &ca));
    }
    if ( cacheret==LCRZO_ERR_OK ) 
    { /* we remove it from the cache */
      lcrzo_er(lcrzo_list_remove_criteria_all(&ptrcv->list_system_arpcache, 
					      &lcrzo_priv_conf_arp_cmpwdev,
					      &ca));
    }
  }
  else
  { ptrcv->compute_sys_arpcache=LCRZO_TRUE;
    if ( cacheret==LCRZO_ERR_OK ) 
    { /* we found it, so we replace it */
      lcrzo_er(lcrzo_list_replace_pos(&ptrcv->list_system_arpcache,
				      cachepos, &ca));
    }
    else
    { /* we add it to the list */
      lcrzo_er(lcrzo_list_add_last(&ptrcv->list_system_arpcache, &ca));
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arp_add_user(lcrzo_bool priorityoversystem,
                            const lcrzo_device device,
		            const lcrzo_etha etha,
		            lcrzo_ipl ipl,
		            lcrzo_bool ispermanent)
{ lcrzo_priv_conf_arp ca, permfoundca, cachefoundca;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_time currenttime;
  lcrzo_int32 permpos, cachepos;
  int permret, cacheret;

  /* initialize the structure */
  ca.priority=priorityoversystem;
  memcpy(ca.eth, etha, LCRZO_ETHA_MAXBYTES);
  lcrzo_er(lcrzo_device_init(device, ca.device));
  ca.ip=ipl;
  ca.ispermanent=ispermanent;
  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_get_sec(&currenttime, &(ca.timeset)));

  /* search it in the lists */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  permret=lcrzo_list_search_all(&ptrcv->list_user_arpperm,
				&lcrzo_priv_conf_arp_cmpwdev,
				&ca, &permpos, &permfoundca);
  if ( permret!=LCRZO_ERR_OKSEARCHNOTFOUND && permret!=LCRZO_ERR_OK )
    return(permret);
  cacheret=lcrzo_list_search_all(&ptrcv->list_user_arpcache,
				 &lcrzo_priv_conf_arp_cmpwdev,
				 &ca, &cachepos, &cachefoundca);
  if ( cacheret!=LCRZO_ERR_OKSEARCHNOTFOUND && cacheret!=LCRZO_ERR_OK )
    return(cacheret);

  /* if the user doesn't know the device, we look if we already know it */
  if ( strlen(ca.device)==0 )
  { if ( permret==LCRZO_ERR_OK && strlen(permfoundca.device)!=0 )
    { lcrzo_er(lcrzo_device_init(permfoundca.device, ca.device));
    }
    else if ( cacheret==LCRZO_ERR_OK && strlen(cachefoundca.device)!=0 )
    { lcrzo_er(lcrzo_device_init(cachefoundca.device, ca.device));
    }
  }

  if ( ispermanent )
  { ptrcv->compute_conf_arpperm=LCRZO_TRUE;
    if ( permret==LCRZO_ERR_OK ) 
    { /* we found it, so we replace it */
      lcrzo_er(lcrzo_list_replace_pos(&ptrcv->list_user_arpperm, 
				      permpos, &ca));
    }
    else
    { /* we add it to the list */
      lcrzo_er(lcrzo_list_add_last(&ptrcv->list_user_arpperm, &ca));
    }
    if ( cacheret==LCRZO_ERR_OK ) 
    { /* we remove it from the cache */
      lcrzo_er(lcrzo_list_remove_criteria_all(&ptrcv->list_user_arpcache, 
					      &lcrzo_priv_conf_arp_cmpwdev,
					      &ca));
    }
  }
  else
  { ptrcv->compute_conf_arpperm=LCRZO_TRUE;
    if ( cacheret==LCRZO_ERR_OK ) 
    { /* we found it, so we replace it */
      lcrzo_er(lcrzo_list_replace_pos(&ptrcv->list_user_arpcache,
				      cachepos, &ca));
    }
    else
    { /* we add it to the list */
      lcrzo_er(lcrzo_list_add_last(&ptrcv->list_user_arpcache, &ca));
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arp_del_system(const lcrzo_device device,
		              const lcrzo_etha etha,
		              lcrzo_ipl ipl)
{ lcrzo_priv_conf_arp ca;
  lcrzo_priv_confvars *ptrcv;
 
  /* initialize the structure */
  ca.priority=LCRZO_FALSE;
  lcrzo_er(lcrzo_device_init(device, ca.device));
  memcpy(ca.eth, etha, LCRZO_ETHA_MAXBYTES);
  ca.ip=ipl;

  /* add it from the list */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_add_last(&ptrcv->list_systemdel_arpperm, &ca));
  lcrzo_er(lcrzo_list_add_last(&ptrcv->list_systemdel_arpcache, &ca));
  ptrcv->compute_sys_arpperm=LCRZO_TRUE;
  ptrcv->compute_sys_arpcache=LCRZO_TRUE;

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arp_del_user(const lcrzo_device device,
		            const lcrzo_etha etha,
		            lcrzo_ipl ipl)
{ lcrzo_priv_conf_arp ca;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_int32 count1, count2;
 
  /* initialize the structure */
  ca.priority=LCRZO_FALSE;
  lcrzo_er(lcrzo_device_init(device, ca.device));
  memcpy(ca.eth, etha, LCRZO_ETHA_MAXBYTES);
  ca.ip=ipl;

  /* remove it from the list */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_count(&ptrcv->list_user_arpperm, &count1));
  lcrzo_er(lcrzo_list_remove_criteria_all(&ptrcv->list_user_arpperm, 
					  &lcrzo_priv_conf_arp_cmp,
					  &ca));
  lcrzo_er(lcrzo_list_count(&ptrcv->list_user_arpperm, &count2));
  if (count1!=count2)
  { ptrcv->compute_conf_arpperm=LCRZO_TRUE;
  }

  lcrzo_er(lcrzo_list_count(&ptrcv->list_user_arpcache, &count1));
  lcrzo_er(lcrzo_list_remove_criteria_all(&ptrcv->list_user_arpcache, 
					  &lcrzo_priv_conf_arp_cmp,
					  &ca));
  lcrzo_er(lcrzo_list_count(&ptrcv->list_user_arpcache, &count2));
  if (count1!=count2)
  { ptrcv->compute_conf_arpcache=LCRZO_TRUE;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arp_count(lcrzo_int32 *pcount)
{ lcrzo_int32 count;
  lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));

  if ( pcount!=NULL )
  { lcrzo_er(lcrzo_list_count(&ptrcv->list_conf_arpperm, &count));
    *pcount = count;
    lcrzo_er(lcrzo_list_count(&ptrcv->list_conf_arpcache, &count));
    *pcount += count;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arp_value_pos(lcrzo_int32 pos,
			     lcrzo_device device,
			     lcrzo_etha etha,
			     lcrzo_ipl *pipl,
			     lcrzo_bool *pispermanent,
			     lcrzo_uint32 *ptimeset)
{ lcrzo_priv_conf_arp ca;
  lcrzo_int32 permcount, cachecount;
  lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));

  /* calculate the position */
  lcrzo_er(lcrzo_list_count(&ptrcv->list_conf_arpperm, &permcount));
  lcrzo_er(lcrzo_list_count(&ptrcv->list_conf_arpcache, &cachecount));
  if ( pos<0 )
  { pos=permcount+cachecount+1+pos;
    if ( pos<=0 ) return(LCRZO_ERR_PATOOLOW);
  }
 
  /* get the value from the correct list */
  if ( pos<=permcount )
  { lcrzo_er(lcrzo_list_value_pos(&ptrcv->list_conf_arpperm, pos, &ca));
  }
  else
  { pos-=permcount;
    lcrzo_er(lcrzo_list_value_pos(&ptrcv->list_conf_arpcache, pos, &ca));
  }
 
  /* set the output parameters */
  lcrzo_er(lcrzo_device_init(ca.device, device));
  if ( etha!=NULL ) memcpy(etha, ca.eth, LCRZO_ETHA_MAXBYTES);
  if ( pipl!=NULL ) *pipl=ca.ip;
  if ( pispermanent!=NULL ) *pispermanent=ca.ispermanent;
  if ( ptimeset!=NULL ) *ptimeset=ca.timeset;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arp_fprint(LCRZOFILE *pf)
{ lcrzo_int32 count, i, strlen_device;
  lcrzo_time currenttime;
  lcrzo_ips ips;
  lcrzo_device device;
  lcrzo_etha etha;
  lcrzo_ipl ipl;
  lcrzo_bool ispermanent;
  lcrzo_uint32 timeset, currenttimesec;
  char c;
  
  lcrzo_er(lcrzo_conf_arp_count(&count));
  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_get_sec(&currenttime, &currenttimesec));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_conf_arp_value_pos(i, device, etha, &ipl,
				      &ispermanent, &timeset));
    strlen_device=strlen(device);
    if (strlen_device>27)
    { c=device[strlen_device-27];
      device[strlen_device-27]='\0';
      fprintf(pf, "  %s...\n", device);
      device[strlen_device-27]=c;
      fprintf(pf, "  ");
      lcrzo_priv_fprint_cstsized(pf, device+strlen_device-27, 28);
    }
    else
    { fprintf(pf, "  ");
      lcrzo_priv_fprint_cstsized(pf, device, 28);
    }
    lcrzo_er(lcrzo_etha_fprint(pf, "", etha, "  "));
    lcrzo_er(lcrzo_ips_init_ipl(ipl, ips));
    lcrzo_priv_fprint_cstsized(pf, ips, 16);
    if ( ispermanent )
      fprintf(pf, "(permanent)\n");
    else 
      lcrzo_uint32_fprint(pf, "(-", currenttimesec - timeset, "%u", "s)\n");
  }

  return(LCRZO_ERR_OK);
}


/*-------------------------------------------------------------*/
int lcrzo_priv_conf_routes_add_system(const lcrzo_device device,
			         lcrzo_ipl dest,
			         lcrzo_ipl mask,
			         lcrzo_ipl ipsource,
			         lcrzo_ipl gateway,
                                 lcrzo_uint32 metric,
			         lcrzo_bool isup)
{ lcrzo_priv_conf_routes cr;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_int32 pos;
  int ret;

  lcrzo_bool_verifbof(isup);

  /* initialize the structure */
  cr.priority=LCRZO_FALSE;
  lcrzo_er(lcrzo_device_init(device, cr.device));
  cr.dest=dest;
  cr.mask=mask;
  cr.ipsource=ipsource;
  cr.gateway=gateway;
  cr.metric=metric;
  cr.isup=isup;

  /* search it in the list */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  ret=lcrzo_list_search_all(&ptrcv->list_system_routes,
			    &lcrzo_priv_conf_routes_cmp,
			    &cr, &pos, NULL);
  if ( ret!=LCRZO_ERR_OKSEARCHNOTFOUND && ret!=LCRZO_ERR_OK )
    return(ret);

  if ( ret==LCRZO_ERR_OK ) 
  { /* we found it, so we replace it */
    lcrzo_er(lcrzo_list_replace_pos(&ptrcv->list_system_routes, pos, &cr));
  }
  else
  { /* we add it to the list */
    lcrzo_er(lcrzo_list_add_last(&ptrcv->list_system_routes, &cr));
  }
  ptrcv->compute_sys_routes=LCRZO_TRUE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_add_user(lcrzo_bool priorityoversystem,
                               const lcrzo_device device,
			       lcrzo_ipl dest,
			       lcrzo_ipl mask,
			       lcrzo_ipl ipsource,
			       lcrzo_ipl gateway,
                               lcrzo_uint32 metric,
			       lcrzo_bool isup)
{ lcrzo_priv_conf_routes cr;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_int32 pos;
  int ret;

  lcrzo_bool_verifbof(isup);

  /* initialize the structure */
  cr.priority=priorityoversystem;
  lcrzo_er(lcrzo_device_init(device, cr.device));
  cr.dest=dest;
  cr.mask=mask;
  cr.ipsource=ipsource;
  cr.gateway=gateway;
  cr.metric=metric;
  cr.isup=isup;

  /* search it in the list */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  ret=lcrzo_list_search_all(&ptrcv->list_user_routes,
			    &lcrzo_priv_conf_routes_cmp,
			    &cr, &pos, NULL);
  if ( ret!=LCRZO_ERR_OKSEARCHNOTFOUND && ret!=LCRZO_ERR_OK )
    return(ret);

  if ( ret==LCRZO_ERR_OK ) 
  { /* we found it, so we replace it */
    lcrzo_er(lcrzo_list_replace_pos(&ptrcv->list_user_routes, pos, &cr));
  }
  else
  { /* we add it to the list */
    lcrzo_er(lcrzo_list_add_last(&ptrcv->list_user_routes, &cr));
  }

  ptrcv->compute_conf_routes=LCRZO_TRUE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_del_system(lcrzo_ipl dest,
			         lcrzo_ipl mask,
			         lcrzo_ipl gateway)
{ lcrzo_priv_conf_routes cr;
  lcrzo_priv_confvars *ptrcv;

  /* initialize the structure */
  cr.priority=LCRZO_FALSE;
  cr.dest=dest;
  cr.mask=mask;
  cr.gateway=gateway;

  /* add it to the list */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_add_last(&ptrcv->list_systemdel_routes, &cr));
  ptrcv->compute_sys_routes=LCRZO_TRUE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_del_user(lcrzo_ipl dest,
			       lcrzo_ipl mask,
			       lcrzo_ipl gateway)
{ lcrzo_priv_conf_routes cr;
  lcrzo_priv_confvars *ptrcv;

  /* initialize the structure */
  cr.priority=LCRZO_FALSE;
  cr.dest=dest;
  cr.mask=mask;
  cr.gateway=gateway;

  /* remove it from the list */
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_criteria_all(&ptrcv->list_user_routes, 
					  &lcrzo_priv_conf_routes_cmp,
					  &cr));
  ptrcv->compute_conf_routes=LCRZO_TRUE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_count(lcrzo_int32 *pcount)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));

  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));

  lcrzo_er(lcrzo_list_count(&(ptrcv->list_conf_routes), pcount));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_value_pos(lcrzo_int32 pos,
				lcrzo_device device,
				lcrzo_ipl *pdest,
				lcrzo_ipl *pmask,
				lcrzo_ipl *pipsource,
				lcrzo_ipl *pgateway,
                                lcrzo_uint32 *pmetric,
				lcrzo_bool *pisup)
{ lcrzo_priv_conf_routes cr;
  lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_value_pos(&(ptrcv->list_conf_routes), pos, &cr));
  lcrzo_er(lcrzo_device_init(cr.device, device));
  if ( pdest!=NULL ) *pdest=cr.dest;
  if ( pmask!=NULL ) *pmask=cr.mask;
  if ( pipsource!=NULL ) *pipsource=cr.ipsource;
  if ( pgateway!=NULL ) *pgateway=cr.gateway;
  if ( pmetric!=NULL ) *pmetric=cr.metric;
  if ( pisup!=NULL ) *pisup=cr.isup;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_fprint(LCRZOFILE *pf)
{ lcrzo_int32 count, i, strlen_device;
  lcrzo_priv_conf_routes cr;
  lcrzo_priv_confvars *ptrcv;
  lcrzo_ips ips;
  lcrzo_int16 language;
  char c;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));

  lcrzo_er(lcrzo_list_count(&(ptrcv->list_conf_routes), &count));
  if (count)
  { lcrzo_er(lcrzo_global_get_language(&language));
    if (language==LCRZO_GLOBAL_LANG_FR )
    { fprintf(pf, "  device  destination    /netmask");
      fprintf(pf, "         ip_source       routeur\n");
    }
    else
    { fprintf(pf, "  device  destination    /netmask");
      fprintf(pf, "         ip_source       gateway\n");
    }
  }
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(&(ptrcv->list_conf_routes), i, &cr));
    strlen_device=strlen(cr.device);
    if (strlen_device>7)
    { c=cr.device[strlen_device-7];
      cr.device[strlen_device-7]='\0';
      fprintf(pf, "  %s...\n", cr.device);
      cr.device[strlen_device-7]=c;
      fprintf(pf, "  ");
      lcrzo_priv_fprint_cstsized(pf, cr.device+strlen_device-7, 8);
    }
    else
    { fprintf(pf, "  ");
      lcrzo_priv_fprint_cstsized(pf, cr.device, 8);
    }
    lcrzo_er(lcrzo_ips_init_ipl(cr.dest, ips));
    lcrzo_priv_fprint_cstsized(pf, ips, 15);
    fprintf(pf, "/");
    lcrzo_er(lcrzo_ips_init_ipl(cr.mask, ips));
    lcrzo_priv_fprint_cstsized(pf, ips, 16);
    if ( cr.ipsource==0 && cr.gateway==0 )
    { lcrzo_er(lcrzo_global_get_language(&language));
      if (language==LCRZO_GLOBAL_LANG_FR )
      { fprintf(pf, "device_local                    ");
      }
      else
      { fprintf(pf, "local_device                    ");
      }
    }
    else if ( cr.gateway==0 )
    { lcrzo_er(lcrzo_ips_init_ipl(cr.ipsource, ips));
      lcrzo_priv_fprint_cstsized(pf, ips, 16);
      fprintf(pf, "                ");
    }
    else
    { lcrzo_er(lcrzo_ips_init_ipl(cr.ipsource, ips));
      lcrzo_priv_fprint_cstsized(pf, ips, 16);
      lcrzo_er(lcrzo_ips_init_ipl(cr.gateway, ips));
      lcrzo_priv_fprint_cstsized(pf, ips, 16);
    }
    lcrzo_uint32_fprint(pf, "", cr.metric, "% 2u", ",");
    if (cr.isup)
      fprintf(pf, "up");
    else
      fprintf(pf, "down");
    fprintf(pf, "\n");
  }
  return(LCRZO_ERR_OK);
}


/*-------------------------------------------------------------*/
int lcrzo_conf_set_sysrenew_allow(lcrzo_bool yes)
{ lcrzo_priv_confvars *ptr;

  lcrzo_bool_verifbof(yes);
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_allow=yes;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_get_sysrenew_allow(lcrzo_bool *pyes)
{ lcrzo_priv_confvars *ptr;

  if (pyes!=NULL)
  { lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
    *pyes=ptr->sysrenew_allow;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_set_sysrenew_allow_devices(lcrzo_bool yes)
{ lcrzo_priv_confvars *ptr;

  lcrzo_bool_verifbof(yes);
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_allow_devices=yes;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_get_sysrenew_allow_devices(lcrzo_bool *pyes)
{ lcrzo_priv_confvars *ptr;

  if (pyes!=NULL)
  { lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
    *pyes=ptr->sysrenew_allow_devices;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_set_sysrenew_allow_arpperm(lcrzo_bool yes)
{ lcrzo_priv_confvars *ptr;

  lcrzo_bool_verifbof(yes);
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_allow_arpperm=yes;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_get_sysrenew_allow_arpperm(lcrzo_bool *pyes)
{ lcrzo_priv_confvars *ptr;

  if (pyes!=NULL)
  { lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
    *pyes=ptr->sysrenew_allow_arpperm;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_set_sysrenew_allow_arpcache(lcrzo_bool yes)
{ lcrzo_priv_confvars *ptr;

  lcrzo_bool_verifbof(yes);
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_allow_arpcache=yes;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_get_sysrenew_allow_arpcache(lcrzo_bool *pyes)
{ lcrzo_priv_confvars *ptr;

  if (pyes!=NULL)
  { lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
    *pyes=ptr->sysrenew_allow_arpcache;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_set_sysrenew_allow_routes(lcrzo_bool yes)
{ lcrzo_priv_confvars *ptr;

  lcrzo_bool_verifbof(yes);
  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_allow_routes=yes;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_get_sysrenew_allow_routes(lcrzo_bool *pyes)
{ lcrzo_priv_confvars *ptr;

  if (pyes!=NULL)
  { lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
    *pyes=ptr->sysrenew_allow_routes;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_set_permentriesperiod(lcrzo_uint32 period)
{ lcrzo_priv_confvars *ptr;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->permentriesperiod=period;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_get_permentriesperiod(lcrzo_uint32 *pperiod)
{ lcrzo_priv_confvars *ptr;

  if (pperiod!=NULL)
  { lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
    *pperiod=ptr->permentriesperiod;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_set_cacheentriestimeout(lcrzo_uint32 timeout)
{ lcrzo_priv_confvars *ptr;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->cacheentriestimeout=timeout;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_get_cacheentriestimeout(lcrzo_uint32 *ptimeout)
{ lcrzo_priv_confvars *ptr;

  if (ptimeout!=NULL)
  { lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
    *ptimeout=ptr->cacheentriestimeout;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_renewnow_system(void)
{ lcrzo_priv_confvars *ptr;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_now=LCRZO_TRUE;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_devices_renewnow_system(void)
{ lcrzo_priv_confvars *ptr;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_now_devices=LCRZO_TRUE;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arpperm_renewnow_system(void)
{ lcrzo_priv_confvars *ptr;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_now_arpperm=LCRZO_TRUE;
  return(LCRZO_ERR_OK);  
}


/*-------------------------------------------------------------*/
int lcrzo_conf_arpcache_renewnow_system(void)
{ lcrzo_priv_confvars *ptr;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_now_arpcache=LCRZO_TRUE;
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_renewnow_system(void)
{ lcrzo_priv_confvars *ptr;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptr));
  ptr->sysrenew_now_routes=LCRZO_TRUE;
  return(LCRZO_ERR_OK);  
}


/*-------------------------------------------------------------*/
int lcrzo_conf_flush_system(void)
{ 
  lcrzo_er(lcrzo_conf_devices_flush_system());
  lcrzo_er(lcrzo_conf_arpperm_flush_system());
  lcrzo_er(lcrzo_conf_arpcache_flush_system());
  lcrzo_er(lcrzo_conf_routes_flush_system());
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_devices_flush_system(void)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_all(&ptrcv->list_system_devices));
  ptrcv->compute_sys_devices=LCRZO_TRUE;
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arpperm_flush_system(void)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_all(&ptrcv->list_system_arpperm));
  ptrcv->compute_sys_arpperm=LCRZO_TRUE;
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arpcache_flush_system(void)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_all(&ptrcv->list_system_arpcache));
  ptrcv->compute_sys_arpcache=LCRZO_TRUE;
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_flush_system(void)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_all(&ptrcv->list_system_routes));
  ptrcv->compute_sys_routes=LCRZO_TRUE;
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_flush_user(void)
{ 
  lcrzo_er(lcrzo_conf_devices_flush_user());
  lcrzo_er(lcrzo_conf_arpperm_flush_user());
  lcrzo_er(lcrzo_conf_arpcache_flush_user());
  lcrzo_er(lcrzo_conf_routes_flush_user());
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_devices_flush_user(void)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_all(&ptrcv->list_user_devices));
  ptrcv->compute_conf_devices=LCRZO_TRUE;
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arpperm_flush_user(void)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_all(&ptrcv->list_user_arpperm));
  ptrcv->compute_conf_arpperm=LCRZO_TRUE;
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_arpcache_flush_user(void)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_all(&ptrcv->list_user_arpcache));
  ptrcv->compute_conf_arpcache=LCRZO_TRUE;
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));
  return(LCRZO_ERR_OK);  
}

/*-------------------------------------------------------------*/
int lcrzo_conf_routes_flush_user(void)
{ lcrzo_priv_confvars *ptrcv;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_list_remove_all(&ptrcv->list_user_routes));
  ptrcv->compute_conf_routes=LCRZO_TRUE;
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));
  return(LCRZO_ERR_OK);  
}


/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
int lcrzo_conf_route_to_host(lcrzo_ipl hostipl,
			     lcrzo_device device,
			     lcrzo_etha srcetha,
			     lcrzo_etha destetha,
			     lcrzo_ipl *psrcipl,
			     lcrzo_ipl *prouteripl)
{ lcrzo_int32 count, i;
  lcrzo_priv_conf_routes cr;
  lcrzo_priv_confvars *ptrcv;
  int ret;

  lcrzo_er(lcrzo_priv_confvars_ptr_get(&ptrcv));
  lcrzo_er(lcrzo_priv_conf_eventuallyupdate(ptrcv));

  lcrzo_er(lcrzo_list_count(&ptrcv->list_conf_routes, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(&ptrcv->list_conf_routes, i, &cr));
    /* if this route matches */
    if ( cr.isup &&
	 ( (hostipl&cr.mask) == (cr.dest&cr.mask) ) )
    { /* set info we know */
      lcrzo_er(lcrzo_device_init(cr.device, device));
      lcrzo_er(lcrzo_etha_init_device(cr.device, srcetha));
      if (psrcipl!=NULL) *psrcipl=cr.ipsource;
      /* set more info */
      if ( cr.ipsource==0 && cr.gateway==0 )
      { /* it is a local device */
        return(LCRZO_ERR_OKROUTELOCALDEV);
      }
      else if ( cr.gateway==0 )
      { /* it is on the lan */
        if ( prouteripl!=NULL ) *prouteripl=0;
	ret=lcrzo_etha_init_ipl(hostipl, destetha);
        if ( ret==LCRZO_ERR_OK ) {}
	else if ( ret==LCRZO_ERR_OKUNRESOLVED ) 
        { return(LCRZO_ERR_OKROUTEHOSTUNREACH);
	}
	else return(ret);
      }
      else
      { /* it is after a router */
        if ( prouteripl!=NULL ) *prouteripl=cr.gateway;
	ret=lcrzo_etha_init_ipl(cr.gateway, destetha);
        if ( ret==LCRZO_ERR_OK ) {}
	else if ( ret==LCRZO_ERR_OKUNRESOLVED ) 
        { return(LCRZO_ERR_OKROUTEGWUNREACH);
	}
	else return(ret);
      }
      /* all the info are set */
      return(LCRZO_ERR_OK);
    }    
  }
  return(LCRZO_ERR_OKROUTENOTFOUND);
}

/*-------------------------------------------------------------*/
int lcrzo_conf_debug_fprint(LCRZOFILE *pf)
{
#ifdef LCRZODEF_SYSTEM_Unix
#elif defined LCRZODEF_SYSTEM_Windows
  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  lcrzo_priv_conf_packetgetadapternames_debug_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  lcrzo_priv_conf_localeth_init_debug_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  lcrzo_priv_conf_localip_init_debug_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  lcrzo_priv_conf_validdhcpinfo_init_debug_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  lcrzo_priv_conf_etha_init_cardnumber_debug_fprint(pf);
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif

  fprintf(pf, "\n------------------------------------------------------------\n");
  fprintf(pf, "Complete configuration\n");
  lcrzo_conf_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  fprintf(pf, "First correct device configuration (lcrzo_priv_conf_init_dev)\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_dev());
  lcrzo_conf_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  fprintf(pf, "First correct arpcache configuration (lcrzo_priv_conf_init_arpcache)\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_arpcache());
  lcrzo_conf_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  fprintf(pf, "First correct rarpcache configuration (lcrzo_priv_conf_init_rarpcache)\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_rarpcache());
  lcrzo_conf_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  fprintf(pf, "First correct routes configuration (lcrzo_priv_conf_init_routes)\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_routes());
  lcrzo_conf_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  fprintf(pf, "Device private configuration\n");
  lcrzo_priv_conf_dev_debug_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  fprintf(pf, "Arp cache private configuration\n");
  lcrzo_priv_conf_arpcache_debug_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  fprintf(pf, "Rarp cache private configuration\n");
  lcrzo_priv_conf_rarpcache_debug_fprint(pf);

  fprintf(pf, "\n\n------------------------------------------------------------\n");
  fprintf(pf, "------------------------------------------------------------\n");
  fprintf(pf, "Routes private configuration\n");
  lcrzo_priv_conf_routes_debug_fprint(pf);

  fprintf(pf, "\n------------------------------------------------------------\n");
  return(LCRZO_ERR_OK);
}



