/* This file is part of Lcrzo.
*/

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_system_verify_routes(lcrzo_priv_confvars *ptr)
{ lcrzo_int32 count, i, cdcount, cdi;
  lcrzo_priv_conf_devices cd;
  lcrzo_priv_conf_routes cr;
  lcrzo_device device;
  lcrzo_bool needtoupdateip, needtoupdatedev;

  /* eventually update gateway and device */

  lcrzo_er(lcrzo_list_count(&(ptr->list_system_routes), &count));
  for ( i=1 ; i<=count ; i++ )
  { needtoupdatedev=LCRZO_FALSE;
    needtoupdateip=LCRZO_FALSE;
    lcrzo_er(lcrzo_list_value_pos(&(ptr->list_system_routes), i, &cr));
    lcrzo_er(lcrzo_list_count(&(ptr->list_system_devices), &cdcount));
    for ( cdi=1 ; cdi<=cdcount ; cdi++ )
    { lcrzo_er(lcrzo_list_value_pos(&(ptr->list_system_devices), cdi, &cd));
      if ( cr.ipsource!=0 )
      { /* need to set device */
        if ( cr.ipsource == cd.ip )
	{ /* ipsource was found in the device list */
          lcrzo_device_init(cd.device, device);
	  needtoupdatedev=LCRZO_TRUE;
  	  break;
	}
      }
      else
      { /* need to set ipsource and device */
        if ( cr.gateway!=0 )
	{ /* need to find the route to this gateway */
          if ( (cd.ip&cd.netmask) ==  (cr.gateway&cd.netmask) )
	  { cr.ipsource=cd.ip;
            lcrzo_device_init(cd.device, device);
	    needtoupdatedev=LCRZO_TRUE;
	    needtoupdateip=LCRZO_TRUE;
	    break;
  	  }
	}
	else
	{ /* need to find the route to ... */
	  if ( cd.ip == cr.dest )
	  { /* ... the device */
	    cr.ipsource=0;
	    lcrzo_device_init(cd.device, device);
	    needtoupdatedev=LCRZO_TRUE;
	    needtoupdateip=LCRZO_TRUE;
	    break;
	  }
	  if ( cd.netmask == cr.mask &&
	       (cd.ip&cd.netmask) == cr.dest )
	  { /* ... the lan */
            cr.ipsource=cd.ip;
            lcrzo_device_init(cd.device, device);
	    needtoupdatedev=LCRZO_TRUE;
	    needtoupdateip=LCRZO_TRUE;
	    break;
	  }
	}
      }
    }

    /* verify the device we want to set */
    if (needtoupdatedev)
    { /* if they are equal, do not update*/
      if ( lcrzo_device_equal(device, cr.device) )
      { needtoupdatedev=LCRZO_FALSE;
      }
      else
      { if ( strlen(device)==0 )
        { needtoupdatedev=LCRZO_FALSE;
        }
        else
	{ lcrzo_device_init(device, cr.device);
	}
      }
    }
 
    /* eventually update */
    if ( needtoupdatedev || needtoupdateip )
    { lcrzo_er(lcrzo_list_replace_pos(&(ptr->list_system_routes), i, &cr));
    }
  }

  /* sort the routes : from "host routes" to "default route" */
  lcrzo_er(lcrzo_list_sort_all(&(ptr->list_system_routes),
			       lcrzo_priv_conf_routes_sortcmp, 
			       NULL));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_system_renew(lcrzo_priv_confvars *ptr)
{ int ret;

  /* remove all permanent entries */
  lcrzo_er(lcrzo_list_remove_all(&ptr->list_system_devices));
  lcrzo_er(lcrzo_list_remove_all(&ptr->list_system_arpperm));
  lcrzo_er(lcrzo_list_remove_all(&ptr->list_system_routes));

  /* remove all intermediate values */
  lcrzo_er(lcrzo_list_remove_all(&ptr->list_devicenumbername));
  lcrzo_er(lcrzo_list_remove_all(&ptr->list_localeth));
  lcrzo_er(lcrzo_list_remove_all(&ptr->list_localip));
  lcrzo_er(lcrzo_list_remove_all(&ptr->list_validdhcpinfo));

  /* set the new permanent values*/
#if 1
  ret=lcrzo_priv_conf_init_dev();
  if ( ret!=LCRZO_ERR_OK && ret!=LCRZO_ERR_IEUNIMPLEMENTED ) return(ret);
  ret=lcrzo_priv_conf_init_arpcache();
  if ( ret!=LCRZO_ERR_OK && ret!=LCRZO_ERR_IEUNIMPLEMENTED ) return(ret);
  ret=lcrzo_priv_conf_init_rarpcache();
  if ( ret!=LCRZO_ERR_OK && ret!=LCRZO_ERR_IEUNIMPLEMENTED ) return(ret);
  ret=lcrzo_priv_conf_init_routes();
  if ( ret!=LCRZO_ERR_OK && ret!=LCRZO_ERR_IEUNIMPLEMENTED ) return(ret);
#else
  /* just an example for debugging */
  { lcrzo_etha etha;
    lcrzo_ipl ip, mask;
    lcrzo_etha_init(0, 0x40, 0x95, 0x46, 0x14, 0xCB, etha);
    lcrzo_ipl_init_ips("192.168.10.20", &ip);
    lcrzo_ipl_init_ips("255.255.255.0", &mask);
    lcrzo_priv_conf_devices_add_system("RTL8029", etha, ip, mask, 1500, LCRZO_TRUE, LCRZO_FALSE);
  }
#endif

  /* ignore internal errors. For example, under Windows, if a DLL wasn't
     found, do not display GetLastError. */
  lcrzo_err_purge();
  
  /* We compute ipsource if it is != 0 (not often set by
     system dependant functions)
     We eventually update device (Linux never set aliases, Solaris
     set local devices to "")
     Moreover, sort the routes accordingly to the netmask (FreeBSD
     doesn't do it) */
  lcrzo_er(lcrzo_priv_conf_system_verify_routes(ptr));

  return(LCRZO_ERR_OK);
}


