/* This file is part of Lcrzo.
*/

#ifdef LCRZODEF_SYSTEM_Linux
#elif defined LCRZODEF_SYSTEM_FreeBSD || defined LCRZODEF_SYSTEM_OpenBSD
#elif defined LCRZODEF_SYSTEM_Solaris

/*-------------------------------------------------------------*/
int lcrzo_priv_priv_etha_init_device(const lcrzo_device device,
				     lcrzo_etha etha);
int lcrzo_priv_priv_etha_init_device(const lcrzo_device device,
				     lcrzo_etha etha)
{ int fd;
  dl_phys_addr_req_t pareq;
  lcrzo_uint8 *petha;
  void *buf; /* use of void* otherwise SIGBUS on Solaris 2.5 */


  if (lcrzo_device_equal(device, "lo0"))
  { return(lcrzo_etha_init(0,0,0,0,0,0, etha));
  }

  lcrzo_er(lcrzo_priv_dlpi_open(device, &fd));
  pareq.dl_primitive=DL_PHYS_ADDR_REQ;
  pareq.dl_addr_type=DL_CURR_PHYS_ADDR;

  lcrzo_er(lcrzo_priv_dlpi_putmsg(fd, (char *)&pareq, sizeof(pareq), 0));
  lcrzo_er(lcrzo_data_alloc(2048, (lcrzo_uint8**)&buf));
  lcrzo_er(lcrzo_priv_dlpi_getmsg(fd, DL_PHYS_ADDR_ACK_SIZE, (char*)buf));

  petha=(lcrzo_data)buf+((dl_phys_addr_ack_t*)buf)->dl_addr_offset;
  memcpy(etha, petha, LCRZO_ETHA_MAXBYTES);
  lcrzo_er(lcrzo_data_free((lcrzo_uint8*)buf));

  close(fd);
  return(LCRZO_ERR_OK);
}

#elif defined LCRZODEF_SYSTEM_Windows

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_NTregistery(void);
int lcrzo_priv_conf_init_dev_NTregistery(void)
{ lcrzo_list list, deviplist, devmasklist;
  lcrzo_data devname, ipaddress, netmask;
  lcrzo_int32 devnamesize, ipaddresssize, netmasksize, devipcount, devmaskcount, devi;
  lcrzo_string shortdevname, devkey;
  lcrzo_int32 cardnumber, cardnumbercount, devicenumber;
  lcrzo_uint32 dhcpenabled;
  lcrzo_device device;
  lcrzo_etha etha;
  lcrzo_ipl ipl, mask;
  lcrzo_bool isanalias;
  char *pc;
  int ret;

  /* First, add loopback */
  { lcrzo_etha etha;
    lcrzo_er(lcrzo_etha_initdefault(etha));
    lcrzo_er(lcrzo_priv_conf_devices_add_system("Loopback", etha, 0x7F000001, 0xFF000000u, 1500, 
					                                      LCRZO_TRUE, LCRZO_FALSE));
  }

  /* get device infos */
  lcrzo_er(lcrzo_priv_winreg_datalist_get(HKEY_LOCAL_MACHINE,
           "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage", "Bind",
           &list));
  lcrzo_efr(lcrzo_list_count(&list, &cardnumbercount), lcrzo_list_close(&list));
  devicenumber=0;
  for ( cardnumber=1 ; cardnumber<=cardnumbercount ; cardnumber++ )
  { devicenumber++;
  
    /* get the device full name */
    ret=lcrzo_datalist_valuem_pos(&list, cardnumber, NULL, &devname, &devnamesize);
    if (ret!=LCRZO_ERR_OK) goto badend1;
    devname[devnamesize]='\0';

    /* compute the short device name */
    pc=strrchr((lcrzo_string)devname, '\\');
    if ( pc == NULL ) pc=(lcrzo_string)devname;
    ret=lcrzo_string_initm_text(pc+1, &shortdevname);
    if (ret!=LCRZO_ERR_OK) goto badend2;

    /* construct the key needed to access its parameters */
    ret=lcrzo_string_initm_text("SYSTEM\\CurrentControlSet\\Services\\", &devkey);
    if (ret!=LCRZO_ERR_OK) goto badend3;
    ret=lcrzo_string_appendm_text(shortdevname, &devkey);
    if (ret!=LCRZO_ERR_OK) goto badend3;
    ret=lcrzo_string_appendm_text("\\Parameters\\Tcpip", &devkey);
    if (ret!=LCRZO_ERR_OK) goto badend3;

    /* check if DHCP is enabled */
    ret=lcrzo_priv_winreg_uint32_get(HKEY_LOCAL_MACHINE, devkey, "EnableDHCP", &dhcpenabled);
    if (ret!=LCRZO_ERR_OK) dhcpenabled=LCRZO_FALSE;

    if (dhcpenabled)
    { dhcpenabled=LCRZO_FALSE;
      ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, devkey, "DhcpIPAddress", &ipaddress, &ipaddresssize);
      if (ret==LCRZO_ERR_OK)
      { ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, devkey, "DhcpSubnetMask", &netmask, &netmasksize);
        if (ret==LCRZO_ERR_OK)
        { /* ok, so we really got an address from a DHCP server */
          dhcpenabled=LCRZO_TRUE;
          /* convert to string */
          ipaddress[ipaddresssize]='\0';
          netmask[netmasksize]='\0';
          /* update conf */
          ret=lcrzo_ipl_init_ips((lcrzo_string)ipaddress, &ipl);
          if ( ret!=LCRZO_ERR_OK ) goto badend8_;
          ret=lcrzo_ipl_init_ips((lcrzo_string)netmask, &mask);
          if ( ret!=LCRZO_ERR_OK ) goto badend8_;
          lcrzo_priv_conf_device_init_devicealias(shortdevname, 1, device);
          lcrzo_priv_conf_etha_init_cardnumberdevice(device, devicenumber, cardnumber, LCRZO_FALSE, etha);
          ret=lcrzo_priv_conf_devices_add_system(device, etha, ipl, mask, 1500, LCRZO_TRUE, LCRZO_FALSE);
          if ( ret!=LCRZO_ERR_OK ) goto badend8_;
          /* free */
          lcrzo_data_free(netmask);
        }
        lcrzo_data_free(ipaddress);
      }
    }

    if (!dhcpenabled)  
    { /* ask the IPAddress/SubnetMask value for this key */
      ret=lcrzo_priv_winreg_datalist_get(HKEY_LOCAL_MACHINE, devkey, "IPAddress", &deviplist);
      if ( ret==LCRZO_ERR_OK )
      { /* we ignore errors from the previous request */
        ret=lcrzo_priv_winreg_datalist_get(HKEY_LOCAL_MACHINE, devkey, "SubnetMask", &devmasklist);
        if ( ret!=LCRZO_ERR_OK ) goto badend5;
        ret=lcrzo_list_count(&deviplist, &devipcount);
        if ( ret!=LCRZO_ERR_OK ) goto badend6;
        ret=lcrzo_list_count(&devmasklist, &devmaskcount);
        if ( ret!=LCRZO_ERR_OK ) goto badend6;
        /* check values */
        if (devipcount!=devmaskcount) { ret=LCRZO_ERR_IEINTERNALERROR; goto badend6; }
        /* get values */        
        for ( devi=1 ; devi<=devipcount ; devi++ )
        { /* get the IP address */
          ret=lcrzo_datalist_valuem_pos(&deviplist, devi, NULL, &ipaddress, &ipaddresssize);
          if ( ret!=LCRZO_ERR_OK ) goto badend6;
          ret=lcrzo_datalist_valuem_pos(&devmasklist, devi, NULL, &netmask, &netmasksize);
          if ( ret!=LCRZO_ERR_OK ) goto badend7;
          /* convert to string */
          ipaddress[ipaddresssize]='\0';
          netmask[netmasksize]='\0';
          /* update conf */
          ret=lcrzo_ipl_init_ips((lcrzo_string)ipaddress, &ipl);
          if ( ret!=LCRZO_ERR_OK ) goto badend8;
          ret=lcrzo_ipl_init_ips((lcrzo_string)netmask, &mask);
          if ( ret!=LCRZO_ERR_OK ) goto badend8;
          lcrzo_priv_conf_device_init_devicealias(shortdevname, devi, device);
          if (devi==1)
          { isanalias=LCRZO_FALSE;
          }
          else
          { devicenumber++;
            isanalias=LCRZO_TRUE;
          }
          lcrzo_priv_conf_etha_init_cardnumberdevice(device, devicenumber, cardnumber, isanalias, etha);
          ret=lcrzo_priv_conf_devices_add_system(device, etha, ipl, mask, 1500, LCRZO_TRUE, (lcrzo_bool)((devi==1)?LCRZO_FALSE:LCRZO_TRUE));
          if ( ret!=LCRZO_ERR_OK ) goto badend8;
          /* free */
          lcrzo_data_free(netmask);
          lcrzo_data_free(ipaddress);
        }
        ret=lcrzo_list_close(&devmasklist);
        if ( ret!=LCRZO_ERR_OK ) goto badend5;
        ret=lcrzo_list_close(&deviplist);
        if ( ret!=LCRZO_ERR_OK ) goto badend4;
      }
    }
    lcrzo_string_free(devkey);
    lcrzo_string_free(shortdevname);
    lcrzo_data_free(devname);
  }
  lcrzo_er(lcrzo_list_close(&list));
  return(LCRZO_ERR_OK);

  /**/
badend8_:
  lcrzo_data_free(netmask);
  lcrzo_data_free(ipaddress);
  goto badend4;

  /**/
badend8:
  lcrzo_data_free(netmask);
badend7:
  lcrzo_data_free(ipaddress);
badend6:
  lcrzo_list_close(&devmasklist);
badend5:
  lcrzo_list_close(&deviplist);
badend4:
  lcrzo_string_free(devkey);
badend3:
  lcrzo_string_free(shortdevname);
badend2:
  lcrzo_string_free((lcrzo_string)devname);
badend1:
  lcrzo_list_close(&list);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery5_dev(lcrzo_device device,
                                               lcrzo_ipl ip,
                                               lcrzo_ipl mask,
                                               lcrzo_int32 *pdevicenumber,
                                               lcrzo_int32 cardnumber,
                                               lcrzo_int32 *paddressnumber)
{ lcrzo_etha etha;
  lcrzo_device dev;
  lcrzo_bool isanalias;
  int ret;

  /* compute the corresponding device */
  isanalias=(lcrzo_bool)((*paddressnumber==1)?LCRZO_FALSE:LCRZO_TRUE);
  lcrzo_priv_conf_device_init_devicealias(device, *paddressnumber, dev);            
  lcrzo_priv_conf_etha_init_cardnumberdevice(device, *pdevicenumber, cardnumber, isanalias, etha);
  /*lcrzo_etha_print("etha=", etha, "\n");
  lcrzo_ipl_print("ip=", ip, "\n");*/
  ret=lcrzo_priv_conf_devices_add_system(dev, etha, ip, mask, 1500, 
					 LCRZO_TRUE, isanalias);
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery5_routes(lcrzo_device device,
                                                  lcrzo_ipl ip,
                                                  lcrzo_string routers)
{ lcrzo_ipl gw;
  char *pc, *pcstart;
  lcrzo_device dev;
  int i, ret;

  /* analyze value which may contain a comma separated list of gateways */
  i=1;
  pcstart=pc=routers;
  ret=LCRZO_ERR_OK;
  while(pc!=NULL && ret==LCRZO_ERR_OK)
  { pc=strchr(pcstart, ',');
    if (pc==NULL)
    { ret=lcrzo_ipl_init_ips(pcstart, &gw);
    }
	  else
    { *pc='\0';
	    ret=lcrzo_ipl_init_ips(pcstart, &gw);
	    pcstart=pc+1;
    }
    if (ret==LCRZO_ERR_OK)
    { /* add the route */
      lcrzo_priv_device_init_ascii(device, dev);
      ret=lcrzo_priv_conf_routes_add_system(dev, 0, 0, ip, gw, i, LCRZO_TRUE);
    }
    i++;
	  if (pc!=NULL) *pc='\0';
  }
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery5_dev2(lcrzo_device device,
					                                      lcrzo_string ipaddress,
					                                      lcrzo_string ipmask,
                                                lcrzo_int32 *pdevicenumber,
                                                lcrzo_int32 cardnumber,
                                                lcrzo_int32 *paddressnumber)
{ lcrzo_ipl ip, mask;
  char *pcip, *pcmask;
  int ret, i;

  /* Note : this is strange, but values have to be read from
     right to left (checked with winipcfg) */
  pcip=ipaddress;
  pcmask=ipmask;
  mask=0;
  ret=LCRZO_ERR_OK;
  i=0;
  while( pcip!=NULL && pcmask!=NULL && ret==LCRZO_ERR_OK )
  { /* find ip */
    pcip=strrchr(ipaddress, ',');
    if (pcip==NULL)
    { ret=lcrzo_ipl_init_ips(ipaddress, &ip);
    }
	  else
    { ret=lcrzo_ipl_init_ips(pcip+1, &ip);
	    *pcip='\0';
    }
    if (ret==LCRZO_ERR_OK)
    { /* find mask */
      pcmask=strrchr(ipmask, ',');
      if (pcmask==NULL)
      { ret=lcrzo_ipl_init_ips(ipmask, &mask);
      }
	    else
      { ret=lcrzo_ipl_init_ips(pcmask+1, &mask);
        *pcmask='\0';
      }
    }
    if (ret==LCRZO_ERR_OK)
    { i++;
      /* add the device */
      if (i>1)
      { (*pdevicenumber)++;
        (*paddressnumber)++;
      }
      ret=lcrzo_priv_conf_init_dev_W9xregistery5_dev(device, ip, mask, pdevicenumber, cardnumber, paddressnumber);
    }
  }

  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery5(lcrzo_device device,
					                                 lcrzo_string ipaddress,
					                                 lcrzo_string ipmask,
					                                 lcrzo_string routers,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 cardnumber,
                                           lcrzo_int32 *paddressnumber,
                                           lcrzo_bool *ptrywithdhcp)
{ lcrzo_ipl ip, mask;
  int ret;

  /* first, check with one address only */
  ret=lcrzo_ipl_init_ips(ipaddress, &ip);
  if (ret==LCRZO_ERR_OK)
  { ret=lcrzo_ipl_init_ips(ipmask, &mask);
    if (ret==LCRZO_ERR_OK)
    { /* when both are 0, prehaps use DHCP */
      if ( ip==0 && mask==0 )
      { *ptrywithdhcp=LCRZO_TRUE;
        return(LCRZO_ERR_OK);
      }
      /* add the device */
      ret=lcrzo_priv_conf_init_dev_W9xregistery5_dev(device, ip, mask, pdevicenumber, cardnumber, paddressnumber);
      if (ret==LCRZO_ERR_OK)
      { /* also add the routes */
        ret=lcrzo_priv_conf_init_dev_W9xregistery5_routes(device, ip, routers);
      }
      /* ok, we exit now */
      return(ret);
    }
  }

  /* if we are here, ipaddress and ipmask are lists */
  ret=lcrzo_priv_conf_init_dev_W9xregistery5_dev2(device, ipaddress, ipmask, pdevicenumber, cardnumber, paddressnumber);
  if (ret==LCRZO_ERR_OK)
  { /* also add the routes, with 0 as source address */
    ret=lcrzo_priv_conf_init_dev_W9xregistery5_routes(device, 0, routers);
  }
  return(ret);
}


/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery4(lcrzo_device device,
					                                 lcrzo_conststring keynettrans,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 cardnumber,
                                           lcrzo_int32 *paddressnumber,
                                           lcrzo_bool *ptrywithdhcp);
int lcrzo_priv_conf_init_dev_W9xregistery4(lcrzo_device device,
					                                 lcrzo_conststring keynettrans,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 cardnumber,
                                           lcrzo_int32 *paddressnumber,
                                           lcrzo_bool *ptrywithdhcp)
{ lcrzo_data value, value2, value3;
  lcrzo_int32 valuesize;
  int ret;

  /* get ip address */
  ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, keynettrans, "IPAddress",
						         &value, &valuesize);
  if (ret!=LCRZO_ERR_OK) return(ret);
  value[valuesize]='\0';
  
  /* get netmask */
  ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, keynettrans, "IPMask",
				 &value2, &valuesize);
  if (ret!=LCRZO_ERR_OK)
  { lcrzo_data_free(value);
    return(ret);
  }
  value2[valuesize]='\0';

  /* get routers */ 
  ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, keynettrans, 
				                             "DefaultGateway", &value3, &valuesize);
  if (ret==LCRZO_ERR_OK)
  { value3[valuesize]='\0';
  }
  else
  { ret=lcrzo_string_initm_text("", (lcrzo_string*)&value3);
    if (ret!=LCRZO_ERR_OK)
    { lcrzo_data_free(value);
      lcrzo_data_free(value2);
      return(ret);
    }
  }

  /* set all IP addresses */
  ret=lcrzo_priv_conf_init_dev_W9xregistery5(device, (lcrzo_string)value, (lcrzo_string)value2, (lcrzo_string)value3, 
                                             pdevicenumber, cardnumber, paddressnumber, ptrywithdhcp);
  lcrzo_data_free(value);
  lcrzo_data_free(value2);
  lcrzo_data_free(value3);

  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery3(lcrzo_device device,
					                                 lcrzo_conststring keylongmstcpi,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 cardnumber,
                                           lcrzo_int32 *paddressnumber,
                                           lcrzo_bool *ptrywithdhcp);
int lcrzo_priv_conf_init_dev_W9xregistery3(lcrzo_device device,
					                                 lcrzo_conststring keylongmstcpi,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 cardnumber,
                                           lcrzo_int32 *paddressnumber,
                                           lcrzo_bool *ptrywithdhcp)
{ lcrzo_data value;
  lcrzo_int32 valuesize;
  lcrzo_string keynettrans;
  int ret;

  /*printf("%s : %s\n", device, keylongmstcpi);*/

  /* check it is TCP/IP */
  ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, keylongmstcpi,
				 "DeviceDesc", &value, &valuesize);
  if (ret==LCRZO_ERR_OK)
  { value[valuesize]='\0';
    if ( strcmp((lcrzo_string)value, "TCP/IP") )
	  ret=LCRZO_ERR_OKUNRESOLVED;
    lcrzo_data_free(value);
  }
  /* simply ignore previous errors */
  if (ret!=LCRZO_ERR_OK) return(LCRZO_ERR_OK);
  /*puts("It is TCP/IP");*/

  /* get the nettrans key */ 
  ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, keylongmstcpi, "Driver",
				 &value, &valuesize);
  if (ret==LCRZO_ERR_OK)
  { value[valuesize]='\0';
    ret=lcrzo_string_initm_text("System\\CurrentControlSet\\Services\\Class\\", &keynettrans);
    if (ret==LCRZO_ERR_OK)
    { ret=lcrzo_string_appendm_text((lcrzo_string)value, &keynettrans);
      if (ret==LCRZO_ERR_OK)
      { /*printf("nettrans=%s\n", keynettrans);*/
	      ret=lcrzo_priv_conf_init_dev_W9xregistery4(device, keynettrans, pdevicenumber,
          cardnumber, paddressnumber, ptrywithdhcp);
      }
      lcrzo_string_free(keynettrans);
    }
	  lcrzo_data_free(value);
  }
  
  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery2(lcrzo_conststring keyname,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 *pcardnumber,
                                           lcrzo_int32 *pdhcpaddressnumber);
int lcrzo_priv_conf_init_dev_W9xregistery2(lcrzo_conststring keyname,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 *pcardnumber,
                                           lcrzo_int32 *pdhcpaddressnumber)
{ lcrzo_string keynet, keymstcp, keylongmstcpi;
  lcrzo_data value, value2, keymstcpi;
  lcrzo_int32 valuesize, value2size, keymstcpisize, count, i, addressnumber;
  lcrzo_list list;
  lcrzo_device device;
  lcrzo_bool trywithdhcp;
  int ret;

  /* obtain the name of the key net */
  ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, keyname, "Driver",
						         &value, &valuesize);
  if (ret==LCRZO_ERR_OK)
  { value[valuesize]='\0';
	  /* construct the key containing the device name */
    ret=lcrzo_string_initm_text("System\\CurrentControlSet\\Services\\Class\\", &keynet);
    if (ret==LCRZO_ERR_OK)
    { ret=lcrzo_string_appendm_text((lcrzo_string)value, &keynet);
	    if (ret==LCRZO_ERR_OK)
      { /* ensure it is not PPP */
	      ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, keynet, "PointToPointIP",
						               NULL, NULL);
        if (ret==LCRZO_ERR_OK)
        { lcrzo_string_free(keynet);
	        lcrzo_data_free(value);
		      /* skip it */
		      return(LCRZO_ERR_OK);
        }
        ret=lcrzo_string_appendm_text("\\NDIS", &keynet);
        if (ret==LCRZO_ERR_OK)
        { /* obtain the device name */
		      /*printf("keynet=%s\n", keynet);*/
          ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, keynet, "LogDriverName",
						                 &value2, &value2size);
          if (ret==LCRZO_ERR_OK)
          { value2[value2size]='\0';
	          ret=lcrzo_device_init((lcrzo_string)value2, device);
		        lcrzo_data_free(value2);
          }
        }
      }
	    lcrzo_string_free(keynet);
    }
	  lcrzo_data_free(value);
  }
  /* this device is counted even if it is bad */
  (*pdevicenumber)++;
  (*pcardnumber)++;
  addressnumber=1;
  if (ret!=LCRZO_ERR_OK)
  { /* skip it */
		return(LCRZO_ERR_OK);
  }
  /*printf("Device = %s\n", device);*/

  /* add info corresponding to each device */
  trywithdhcp=LCRZO_FALSE;
  ret=lcrzo_string_initm_text(keyname, &keymstcp);
  if (ret==LCRZO_ERR_OK)
  { ret=lcrzo_string_appendm_text("\\Bindings", &keymstcp);
    if (ret==LCRZO_ERR_OK)
    { ret=lcrzo_priv_winreg_subvallist_get(HKEY_LOCAL_MACHINE, keymstcp, &list);
	    if (ret==LCRZO_ERR_OK)
      { ret=lcrzo_list_count(&list, &count);
	      /*printf("count=%d\n", count);*/
        if (ret==LCRZO_ERR_OK)
        { 
          for ( i=1 ; i<=count && ret==LCRZO_ERR_OK ; i++ )
          { ret=lcrzo_datalist_valuem_pos(&list, i, NULL, &keymstcpi, &keymstcpisize);
            if (ret==LCRZO_ERR_OK)
            { keymstcpi[keymstcpisize]='\0';
			        /*printf("keymstcpi=%s\n", keymstcpi);*/
              ret=lcrzo_string_initm_text("Enum\\Network\\", &keylongmstcpi);
              if (ret==LCRZO_ERR_OK)
              { ret=lcrzo_string_appendm_text((lcrzo_string)keymstcpi, &keylongmstcpi);
                if (ret==LCRZO_ERR_OK)
                { /* verify it is TCP/IP and set values */
			            ret=lcrzo_priv_conf_init_dev_W9xregistery3(device, keylongmstcpi, 
                    pdevicenumber, *pcardnumber, &addressnumber, &trywithdhcp);
                }
				        lcrzo_string_free(keylongmstcpi);
              }
			        lcrzo_data_free(keymstcpi);
            }
          }
        }
		    lcrzo_list_close(&list);
      }
    }
	  lcrzo_string_free(keymstcp);
  }

  if ( trywithdhcp )
  { lcrzo_priv_conf_validdhcpinfo vdi;
    lcrzo_device dev;
    ret=lcrzo_priv_device_init_ascii(device, dev);
    if (ret==LCRZO_ERR_OK)
    { ret=lcrzo_priv_conf_validdhcpinfo_get(dev, *pdhcpaddressnumber, &vdi);
      if (ret==LCRZO_ERR_OK)
      { /* add device */
        (*pdhcpaddressnumber)++;
        ret=lcrzo_priv_conf_devices_add_system(dev, vdi.eth, vdi.ip, vdi.mask, 1500, LCRZO_TRUE, LCRZO_FALSE);
        if (ret==LCRZO_ERR_OK)
        { /* add routes */
          for ( i=0 ; i<LCRZO_PRIV_CONF_VALIDIPINFO_MAXGW && vdi.gw[i]!=0 ; i++ )
          { ret=lcrzo_priv_conf_routes_add_system(dev, 0, 0, vdi.ip, vdi.gw[i], i+1, LCRZO_TRUE);
          }
        }
      }
    }
  }

  return(ret);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery1(lcrzo_conststring keyname1,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 *pcardnumber,
                                           lcrzo_int32 *pdhcpaddressnumber);
int lcrzo_priv_conf_init_dev_W9xregistery1(lcrzo_conststring keyname1,
                                           lcrzo_int32 *pdevicenumber,
                                           lcrzo_int32 *pcardnumber,
                                           lcrzo_int32 *pdhcpaddressnumber)
{ lcrzo_list list2;
  lcrzo_data keyname2, value;
  lcrzo_int32 j, count2, valuesize;
  int ret, retf;

  retf=LCRZO_ERR_OK;
  /* go one step further */
  ret=lcrzo_priv_winreg_subkeylist_get(HKEY_LOCAL_MACHINE, keyname1, &list2);
  if (ret==LCRZO_ERR_OK)
  { ret=lcrzo_list_count(&list2, &count2);
    if (ret==LCRZO_ERR_OK)
    { 
      for ( j=1 ; j<=count2 && ret==LCRZO_ERR_OK ; j++ ) 
      { ret=lcrzo_datalist_valuem_pos(&list2, j, NULL, &keyname2, NULL);
        if (ret==LCRZO_ERR_OK)
        { /*printf("%s\n", keyname2);*/

	        ret=lcrzo_priv_winreg_data_get(HKEY_LOCAL_MACHINE, (lcrzo_string)keyname2, "Class",
						                       &value, &valuesize);
          if (ret==LCRZO_ERR_OK)
          { value[valuesize]='\0';
            /*printf("%s\n", value);*/
            if (!strcmp((lcrzo_string)value, "Net"))
            { /*printf("%s\n", keyname2);*/
              retf=lcrzo_priv_conf_init_dev_W9xregistery2((lcrzo_string)keyname2, pdevicenumber, pcardnumber, pdhcpaddressnumber);
            }
				    lcrzo_data_free(value);
          }
			    lcrzo_data_free(keyname2);
        }
      }	
    } 
    lcrzo_list_close(&list2);
  }
  return(retf);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_W9xregistery(void);
int lcrzo_priv_conf_init_dev_W9xregistery(void)
{ lcrzo_list list0, list1;
  lcrzo_data keyname0, keyname1;
  lcrzo_int32 h, i, count0, count1;
  lcrzo_int32 devicenumber, cardnumber, dhcpaddressnumber;
  int ret, retf;

  /* First, add loopback */
  { lcrzo_etha etha;
    lcrzo_er(lcrzo_etha_initdefault(etha));
    lcrzo_er(lcrzo_priv_conf_devices_add_system("Loopback", etha, 0x7F000001, 0xFF000000u, 1500, 
					                                      LCRZO_TRUE, LCRZO_FALSE));
  }

  retf=LCRZO_ERR_OK;
  devicenumber=0;
  cardnumber=0;
  dhcpaddressnumber=1;
  lcrzo_er(lcrzo_priv_winreg_subkeylist_get(HKEY_LOCAL_MACHINE, "Enum", &list0));
  ret=lcrzo_list_count(&list0, &count0);
  if (ret==LCRZO_ERR_OK)
  { 
    for ( h=1 ; h<=count0 && ret==LCRZO_ERR_OK ; h++ )
    { ret=lcrzo_datalist_valuem_pos(&list0, h, NULL, &keyname0, NULL);
      if (ret==LCRZO_ERR_OK)
      { /*printf("%s\n", keyname0);*/
		    
        /* go one step further */
        ret=lcrzo_priv_winreg_subkeylist_get(HKEY_LOCAL_MACHINE, (lcrzo_string)keyname0, &list1);
        if (ret==LCRZO_ERR_OK)
        { ret=lcrzo_list_count(&list1, &count1);
          if (ret==LCRZO_ERR_OK)
          { 
            for ( i=1 ; i<=count1 && ret==LCRZO_ERR_OK ; i++ )
            { ret=lcrzo_datalist_valuem_pos(&list1, i, NULL, &keyname1, NULL);
              if (ret==LCRZO_ERR_OK)
              { 
	    	        /*printf("%s\n", keyname1);*/
                retf=lcrzo_priv_conf_init_dev_W9xregistery1((lcrzo_string)keyname1, &devicenumber, &cardnumber, &dhcpaddressnumber);
                lcrzo_data_free(keyname1);
              }
            }
          }
          lcrzo_list_close(&list1);
        }
        lcrzo_data_free(keyname0);
      }
    }
  }
  lcrzo_list_close(&list0);
  
  return(retf);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_snmpdll(void);
int lcrzo_priv_conf_init_dev_snmpdll(void)
{ lcrzo_priv_snmpdll snmpdll;
  lcrzo_priv_snmpdllreq snmpdllreqip, snmpdllreqdev;
  AsnObjectIdentifier oid0, oid1, oid2, oid3;
  lcrzo_uint32 i, numberofcards, mtu, mactype, ifindexip, ifindexdev, ifindexprevious;
  lcrzo_ipl ipaddress, ipnetmask;
  lcrzo_etha etha;
  lcrzo_bool isanalias, foundinterface;

  //lcrzo_priv_snmpdll_printall();

  /* load the DLL, and init functions */
  lcrzo_er(lcrzo_priv_snmpdll_init(&snmpdll));

  /* get the number of interfaces */
  lcrzo_er(lcrzo_priv_AsnOid_init(&oid0, 1, 3, 6, 1, 2, 1, 2, 1, -1));
  lcrzo_er(lcrzo_priv_snmpdllreq_init(&snmpdllreqdev, &oid0, NULL, NULL, NULL, NULL));
  lcrzo_er(lcrzo_priv_AsnOid_close(&oid0));
  lcrzo_er(lcrzo_priv_snmpdllreq_getnext(&snmpdll, &snmpdllreqdev));
  //lcrzo_er(lcrzo_priv_snmpdllreq_print(&snmpdllreqdev));
  lcrzo_er(lcrzo_priv_snmpdllreq__uint32(&snmpdllreqdev, 0, &numberofcards));
  //printf("Number of cards = %d\n", numberofcards);
  lcrzo_er(lcrzo_priv_snmpdllreq_close(&snmpdllreqdev));

  /* just for the compiler warning */
  ifindexdev=0;
  mtu=0;
  
  /* get characteristics of the IP addresses */
  lcrzo_er(lcrzo_priv_AsnOid_init(&oid0, 1, 3, 6, 1, 2, 1, 4, 20, 1, 1, -1));
  lcrzo_er(lcrzo_priv_AsnOid_init(&oid1, 1, 3, 6, 1, 2, 1, 4, 20, 1, 2, -1));
  lcrzo_er(lcrzo_priv_AsnOid_init(&oid2, 1, 3, 6, 1, 2, 1, 4, 20, 1, 3, -1));
  lcrzo_er(lcrzo_priv_snmpdllreq_init(&snmpdllreqip, &oid0, &oid1, &oid2, NULL, NULL));
  lcrzo_er(lcrzo_priv_AsnOid_close(&oid0));
  lcrzo_er(lcrzo_priv_AsnOid_close(&oid1));
  lcrzo_er(lcrzo_priv_AsnOid_close(&oid2));
  ifindexprevious=0xFFFFFFFF;
  lcrzo_er(lcrzo_priv_snmpdllreq_getnext(&snmpdll, &snmpdllreqip));
  while ( snmpdllreqip.varBindList.list[0].name.ids[7] == 20 &&
          snmpdllreqip.varBindList.list[0].name.ids[9] == 1)
  { //lcrzo_er(lcrzo_priv_snmpdllreq_print(&snmpdllreqip));
    lcrzo_er(lcrzo_priv_snmpdllreq__uint32(&snmpdllreqip, 0, &ipaddress));
    lcrzo_er(lcrzo_priv_snmpdllreq__uint32(&snmpdllreqip, 1, &ifindexip));
    lcrzo_er(lcrzo_priv_snmpdllreq__uint32(&snmpdllreqip, 2, &ipnetmask));

    /* now find information corresponding to the interface number */
    /* do not ask twice */
    if (ifindexip==ifindexprevious)
    { isanalias=LCRZO_TRUE;
      foundinterface=LCRZO_TRUE;
    }
    else
    { isanalias=LCRZO_FALSE;
      foundinterface=LCRZO_FALSE;
    }
    if ( !foundinterface )
    { lcrzo_er(lcrzo_priv_AsnOid_init(&oid0, 1, 3, 6, 1, 2, 1, 2, 2, 1, 1, -1));
      lcrzo_er(lcrzo_priv_AsnOid_init(&oid1, 1, 3, 6, 1, 2, 1, 2, 2, 1, 3, -1));
      lcrzo_er(lcrzo_priv_AsnOid_init(&oid2, 1, 3, 6, 1, 2, 1, 2, 2, 1, 4, -1));
      lcrzo_er(lcrzo_priv_AsnOid_init(&oid3, 1, 3, 6, 1, 2, 1, 2, 2, 1, 6, -1));
      lcrzo_er(lcrzo_priv_snmpdllreq_init(&snmpdllreqdev, &oid0, &oid1, &oid2, &oid3, NULL));
      lcrzo_er(lcrzo_priv_AsnOid_close(&oid0));
      lcrzo_er(lcrzo_priv_AsnOid_close(&oid1));
      lcrzo_er(lcrzo_priv_AsnOid_close(&oid2));
      lcrzo_er(lcrzo_priv_AsnOid_close(&oid3));
      for ( i=0 ; i<numberofcards ; i++ )
      { lcrzo_er(lcrzo_priv_snmpdllreq_getnext(&snmpdll, &snmpdllreqdev));
        //lcrzo_er(lcrzo_priv_snmpdllreq_print(&snmpdllreqdev));
        lcrzo_er(lcrzo_priv_snmpdllreq__uint32(&snmpdllreqdev, 0, &ifindexdev));
        lcrzo_er(lcrzo_priv_snmpdllreq__uint32(&snmpdllreqdev, 1, &mactype));
        lcrzo_er(lcrzo_priv_snmpdllreq__uint32(&snmpdllreqdev, 2, &mtu));
        lcrzo_er(lcrzo_priv_snmpdllreq__etha(&snmpdllreqdev, 3, etha));
        if ( ifindexdev==ifindexip )
        { foundinterface=LCRZO_TRUE;
          /* if it's not Ethernet */
          if (mactype!=6)
          { lcrzo_er(lcrzo_etha_initdefault(etha));
          }
          break;
        }
      }
      lcrzo_er(lcrzo_priv_snmpdllreq_close(&snmpdllreqdev));
    }
    if (!foundinterface)
    { mtu=0;
      lcrzo_er(lcrzo_etha_initdefault(etha));
    }
    else
    { ifindexprevious = ifindexdev;
    }

    /* add it */
    lcrzo_priv_conf_devicenumbername_devices_add_system(ifindexip, etha, ipaddress, 
                                                   ipnetmask, mtu, LCRZO_TRUE, isanalias);

    lcrzo_er(lcrzo_priv_snmpdllreq_getnext(&snmpdll, &snmpdllreqip));
  }
  lcrzo_er(lcrzo_priv_snmpdllreq_close(&snmpdllreqip));

  /* end */
  lcrzo_er(lcrzo_priv_snmpdll_close(&snmpdll));
  
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_iphlpapidll(void);
int lcrzo_priv_conf_init_dev_iphlpapidll(void)
{ lcrzo_priv_iphlpapidll iphlpapidll;
  lcrzo_uint32 bufsize, i;
  PMIB_IPADDRTABLE pipaddrtable;
  PMIB_IFROW pifrow;
  lcrzo_uint32 mtu, ifindexprevious;
  lcrzo_etha etha;
  lcrzo_uint32 devicenumber;
  lcrzo_bool isanalias;
  int ret;
    
  /* load the library */
  lcrzo_er(lcrzo_priv_iphlpapidll_init(&iphlpapidll));

  /* get the IP table size */
  bufsize=0;
  ret=(iphlpapidll.GetIpAddrTable)(NULL, &bufsize, FALSE);
  if ( ret!=ERROR_INSUFFICIENT_BUFFER )
  { lcrzo_er(lcrzo_priv_iphlpapidll_close(&iphlpapidll));
    return(LCRZO_ERR_FUGETIPADDRTABLE);
  }

  /* allocate data */
  pipaddrtable=(PMIB_IPADDRTABLE)GlobalAlloc(GPTR, bufsize);
  if (pipaddrtable==NULL)
  { lcrzo_er(lcrzo_priv_iphlpapidll_close(&iphlpapidll));
    return(LCRZO_ERR_FUGLOBALALLOC);
  }
  
  /* get the IP table */
  ret=iphlpapidll.GetIpAddrTable(pipaddrtable, &bufsize, FALSE);
  if ( ret!=NO_ERROR )
  { GlobalFree(pipaddrtable);
    lcrzo_er(lcrzo_priv_iphlpapidll_close(&iphlpapidll));
    return(LCRZO_ERR_FUGETIPADDRTABLE);
  }

  /* loop through each entry */
  ifindexprevious=0xFFFFFFFFu;
  for ( i=0 ; i<pipaddrtable->dwNumEntries ; i++ )
  { /* set default interface information */
    mtu=0;
    lcrzo_er(lcrzo_etha_initdefault(etha));
    /* get interface informations */
    pifrow=(PMIB_IFROW)GlobalAlloc(GPTR, sizeof(MIB_IFROW));
    if (pifrow!=NULL)
    { /* search for this index */
      pifrow->dwIndex=pipaddrtable->table[i].dwIndex;
      ret=iphlpapidll.GetIfEntry(pifrow);
      if ( ret==NO_ERROR )
      { /* found the wanted interface */
        if (pifrow->dwType!=6 || pifrow->dwPhysAddrLen!=LCRZO_ETHA_MAXBYTES)
        { /* if it's not Ethernet */
          lcrzo_er(lcrzo_etha_initdefault(etha));
        }
        else
        { lcrzo_etha_init(pifrow->bPhysAddr[0], pifrow->bPhysAddr[1], pifrow->bPhysAddr[2],
                          pifrow->bPhysAddr[3], pifrow->bPhysAddr[4], pifrow->bPhysAddr[5], etha);
        }
        mtu=pifrow->dwMtu;
      }
      GlobalFree(pifrow);
    }
    /* check if it's an alias */
    if ( ifindexprevious == pipaddrtable->table[i].dwIndex )
      isanalias=LCRZO_TRUE;
    else
      isanalias=LCRZO_FALSE;
    ifindexprevious = pipaddrtable->table[i].dwIndex;

    /* add it */
    devicenumber=pipaddrtable->table[i].dwIndex;
    lcrzo_priv_conf_devicenumbername_devices_add_system(devicenumber, etha,
			       lcrzo_htonl(pipaddrtable->table[i].dwAddr),
			       lcrzo_htonl(pipaddrtable->table[i].dwMask),
				       mtu, LCRZO_TRUE, isanalias);
  }

  /* unload the library */
  GlobalFree(pipaddrtable);
  lcrzo_er(lcrzo_priv_iphlpapidll_close(&iphlpapidll));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_gethostbyname(void);
int lcrzo_priv_conf_init_dev_gethostbyname(void)
{ lcrzo_hs hs;
  struct hostent *phe;
  lcrzo_device device;
  lcrzo_etha etha;
  lcrzo_ipl ip, mask;
  int ret, i;
    
  /* First, add loopback */
  lcrzo_er(lcrzo_etha_initdefault(etha));
  lcrzo_er(lcrzo_priv_conf_devices_add_system("Loopback", etha, 0x7F000001, 0xFF000000u, 1500, 
				                                      LCRZO_TRUE, LCRZO_FALSE));

  /* note: we do not start this function with lcrzo_priv_conf_localip_init_gethostbyname,
     otherwise we loose the order (needed by lcrzo_priv_conf_etha_init_cardnumberdevice) */

  /* get the local hostname */
  ret=gethostname(hs, LCRZO_HS_MAXBYTES);
  if (ret!=0) return(LCRZO_ERR_OKUNRESOLVED);

  /* get the corresponding IP addresses */
  phe=gethostbyname(hs);
  if (phe==NULL) return(LCRZO_ERR_OKUNRESOLVED);
  if (phe->h_addrtype!=AF_INET) return(LCRZO_ERR_OKUNRESOLVED);
  if (phe->h_length!=LCRZO_IPA_MAXBYTES) return(LCRZO_ERR_OKUNRESOLVED);

  /* loop through each device */
  i=0;
  while ( phe->h_addr_list[i] != NULL )
  { ip=((lcrzo_uint8)phe->h_addr_list[i][0])<<24;
    ip|=((lcrzo_uint8)phe->h_addr_list[i][1])<<16;
    ip|=((lcrzo_uint8)phe->h_addr_list[i][2])<<8;
    ip|=((lcrzo_uint8)phe->h_addr_list[i][3]);
    if ((ip&0x80000000)==0) mask=0xFF000000u;
		else if ((ip&0xC0000000)==0x80000000) mask=0xFFFF0000u;
		else if ((ip&0xE0000000)==0xC0000000) mask=0xFFFFFF00u;
		else mask=0xFFFFFF00u;
    ret=lcrzo_priv_conf_device_init_ipl(ip, device);
    if (ret!=LCRZO_ERR_OK)
    { lcrzo_priv_conf_device_init_devicealias(hs, i+1, device);
    }
    lcrzo_priv_conf_etha_init_cardnumberdevice(device, i+1, 1, LCRZO_FALSE, etha);
    lcrzo_priv_conf_devices_add_system(device, etha, ip, mask, 1500, 
				                               LCRZO_TRUE, LCRZO_FALSE);
    i++;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_init_dev_packetdll(void);
int lcrzo_priv_conf_init_dev_packetdll(void)
{ lcrzo_int32 cardnumber, i, count;
  lcrzo_ipl ip, mask;
  lcrzo_device device, dev;
  lcrzo_etha etha;
  lcrzo_list list;
  BOOL err;
  int ret;
  
  lcrzo_er(lcrzo_priv_conf_packetgetadapternames(&list));

  /* loop for each adapter name */
  cardnumber=0;
  ret=lcrzo_list_count(&list, &count);
  if (ret==LCRZO_ERR_OK)
  {
    for ( i=1 ; i<=count ; i++ )
    { ret=lcrzo_priv_conf_packetgetadapternames_get(&list, i, device);
      if (ret==LCRZO_ERR_OK)
      { /* get the IP address for this device */
        cardnumber++;
        ret=lcrzo_priv_ascii_init_device(device, dev);
        if (ret==LCRZO_ERR_OK)
        { err=PacketGetNetInfo(dev, &ip, &mask);
          if (err)
          { lcrzo_priv_conf_etha_init_cardnumberdevice(device, cardnumber, cardnumber, LCRZO_FALSE, etha);
            lcrzo_priv_conf_devices_add_system(device, etha, ip, mask, 1500, 
				                                 LCRZO_TRUE, LCRZO_FALSE);
          }
        }
      }
    }
  }
  lcrzo_list_close(&list);
  if (cardnumber==0) return(LCRZO_ERR_OKUNRESOLVED);
  return(LCRZO_ERR_OK);
}

#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif

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

int lcrzo_priv_conf_init_dev(void)
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
#if defined LCRZODEF_SYSTEM_Linux || defined LCRZODEF_SYSTEM_Solaris
{ int fd, i, nbinterface, ret;
  struct ifconf ifc;
  struct ifreq ireqbuf[100];
  struct sockaddr_in soin;
  lcrzo_bool isup, isanalias;
  lcrzo_device device;
  struct ifreq ifr;
  lcrzo_etha etha;
  lcrzo_ipl ipl, netmask;
  lcrzo_uint32 mtu;

  /*on ouvre une socket car c'est la dessus que l'on fait un ioctl*/
  fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd<0) return(LCRZO_ERR_FUSOCKET);

  /*le buffer va comporter toutes les interfaces*/
  ifc.ifc_len = sizeof(ireqbuf); /*taille totale*/
  ifc.ifc_ifcu.ifcu_req = ireqbuf; /*position de depart*/
  memset((char *)ireqbuf, 0, sizeof(ireqbuf));

  /*met dans ifc la config locale*/
  if ( ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 )
  { close(fd);
    return(LCRZO_ERR_FUIOCTL);
  }

  nbinterface = ifc.ifc_len / sizeof(struct ifreq);

  /*parcours la boucle*/
  for ( i=0 ; i<nbinterface ; i++ )
  { lcrzo_efr(lcrzo_device_init(ireqbuf[i].ifr_name, device), close(fd));
    /* get the info from the device */
    memset(&ifr, 0, sizeof(ifr));
    lcrzo_string_init_text(device, sizeof(ifr.ifr_name)-1, ifr.ifr_name);
    ifr.ifr_addr.sa_family = AF_INET;
    if (ioctl(fd, SIOCGIFFLAGS, (char*)&ifr) < 0)
    { close(fd);
      return(LCRZO_ERR_FUIOCTL);
    }
    /* check if up */
    if ( ifr.ifr_flags&IFF_UP )
      isup=1;
    else
      isup=0;
    /* check if it's an alias */
    ret=lcrzo_string_search_char(device, 0, +1, -1, ':', NULL, NULL);
    if (ret==LCRZO_ERR_OKSEARCHNOTFOUND)
      isanalias=0;
    else
      isanalias=1;
    /* get the Ethernet address */
#if defined LCRZODEF_SYSTEM_Solaris
    lcrzo_er(lcrzo_priv_priv_etha_init_device(device, etha));
#elif defined LCRZODEF_SYSTEM_Linux
    memset(&ifr, 0, sizeof(ifr));
    lcrzo_string_init_text(device, sizeof(ifr.ifr_name)-1, ifr.ifr_name);
    ifr.ifr_addr.sa_family = AF_INET;
    if (ioctl(fd, SIOCGIFHWADDR, (char*)&ifr) < 0)
    { close(fd);
      return(LCRZO_ERR_FUIOCTL);
    }
    memcpy(etha, &ifr.ifr_hwaddr.sa_data, LCRZO_ETHA_MAXBYTES);
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif
    /* get the IP address */
    memset(&ifr, 0, sizeof(ifr));
    lcrzo_string_init_text(device, sizeof(ifr.ifr_name)-1, ifr.ifr_name);
    ifr.ifr_addr.sa_family = AF_INET;
    if (ioctl(fd, SIOCGIFADDR, (char*)&ifr) < 0)
    { close(fd);
      return(LCRZO_ERR_FUIOCTL);
    }
    memcpy(&soin, &(ifr.ifr_addr), sizeof(struct sockaddr_in));
    ipl=lcrzo_ntohl(soin.sin_addr.s_addr);
    /* get the netmask */
    memset(&ifr, 0, sizeof(ifr));
    lcrzo_string_init_text(device, sizeof(ifr.ifr_name)-1, ifr.ifr_name);
    ifr.ifr_addr.sa_family = AF_INET;
    if (ioctl(fd, SIOCGIFNETMASK, (char*)&ifr) < 0)
    { close(fd);
      return(LCRZO_ERR_FUIOCTL);
    }
    memcpy(&soin, &(ifr.ifr_addr), sizeof(struct sockaddr_in));
    netmask=lcrzo_ntohl(soin.sin_addr.s_addr);
    /* get the mtu */
    memset(&ifr, 0, sizeof(ifr));
    lcrzo_string_init_text(device, sizeof(ifr.ifr_name)-1, ifr.ifr_name);
    ifr.ifr_addr.sa_family = AF_INET;
    if (ioctl(fd, SIOCGIFMTU, (char*)&ifr) < 0)
    { close(fd);
      return(LCRZO_ERR_FUIOCTL);
    }
#if defined LCRZODEF_SYSTEM_Solaris
    mtu=ifr.ifr_metric;
#else
    mtu=ifr.ifr_mtu;
#endif
    /* save it in the configuration */
    lcrzo_efr(lcrzo_priv_conf_devices_add_system(device, etha, ipl, netmask, mtu,
				     isup, isanalias),
	      close(fd));
  }
          
  ret=close(fd);
  if ( ret == -1 ) return(LCRZO_ERR_FUCLOSE);
  return(LCRZO_ERR_OK);
}
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
#elif defined LCRZODEF_SYSTEM_FreeBSD || defined LCRZODEF_SYSTEM_OpenBSD
{ int mib[6], flags;
  LAURENT_size_t len;
  char *buf, *lim, *next;
  struct  if_msghdr *ifm;
  struct  sockaddr_dl *sdl;
  lcrzo_device device;
  lcrzo_etha etha;
  lcrzo_bool isaninterestingdevice, isup, isanalias;
  lcrzo_uint32 mtu=0;
  lcrzo_ipl ipl, netmask;

  mib[0] = CTL_NET;         /*reseau*/
  mib[1] = PF_ROUTE;        /*famille de protocole*/
  mib[2] = 0;               /*numero de protocole*/
  mib[3] = AF_INET;         /*famille d'adresse*/
  mib[4] = NET_RT_IFLIST;   /*liste des interfaces*/
  mib[5] = 0;

  /*on fait d'abord un premier appel pour connaitre la taille a allouer*/
  if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
  { return (LCRZO_ERR_FUSYSCTL);
  }
  
  /*on alloue la taille necessaire*/
  lcrzo_er(lcrzo_string_alloc(len, &buf));

  /*on fait le vrai appel*/
  if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
  { lcrzo_string_free(buf);
    return (LCRZO_ERR_FUSYSCTL);
  }
  lim = buf + len;

  /*on parcours les elements de la liste trouvee*/
  isaninterestingdevice=LCRZO_FALSE;
  isup=LCRZO_FALSE;
  isanalias=LCRZO_FALSE;
  next = buf;
  while (next < lim)
  { ifm = (struct if_msghdr *)next;
    next += ifm->ifm_msglen;

    /* a new device */
    if (ifm->ifm_type == RTM_IFINFO)
    { sdl = (struct sockaddr_dl *)(ifm + 1);
      if ( sdl->sdl_type==IFT_ETHER || sdl->sdl_type==IFT_LOOP )
      { /* sdl->sdl_nlen contains the device name len, not terminated by 0 */
        if ( sdl->sdl_nlen>LCRZO_DEVICE_MAXBYTES )
	  return(LCRZO_ERR_PAOVERFLOW);
        lcrzo_string_init_text(sdl->sdl_data, LCRZO_DEVICE_MAXBYTES, device);
        device[sdl->sdl_nlen]='\0';
        /* get the Ethernet address */
        memcpy(etha, LLADDR(sdl), LCRZO_ETHA_MAXBYTES);
        /* get the mtu */
        mtu=(ifm->ifm_data).ifi_mtu;
	/* get the up flag */
        flags=ifm->ifm_flags;
        if (flags&IFF_UP) 
          isup=LCRZO_TRUE;
	else 
          isup=LCRZO_FALSE;
        /* its an interesting device */
        isaninterestingdevice=LCRZO_TRUE;
        isanalias=LCRZO_FALSE;
      }
      else
      { isaninterestingdevice=LCRZO_FALSE;
      }
    }

    /* if it's an interesting device */
    if (isaninterestingdevice)
    { /* new addresses for a device */
      if (ifm->ifm_type == RTM_NEWADDR)
      { struct ifa_msghdr *ifam;
        struct sockaddr *psa;
        struct sockaddr_in *psai;
        int ifamaddr, i;
        lcrzo_bool netmaskset, iplset;

        /* it contains ifa_msghdr followed by sockaddrs */
        ifam = (struct ifa_msghdr *)ifm;
        /* ifamaddr contains a bitwise set of sockaddrs types 
           which are in ifm */
        ifamaddr=ifam->ifam_addrs;
        /* initialize the pointer to the first sockaddr */
        psa=(struct sockaddr *)((char*)ifm + sizeof(struct ifa_msghdr));
        /* we look if one of the sockaddr contains ipl or netmask */
	netmaskset=LCRZO_FALSE;
	iplset=LCRZO_FALSE;
        netmask=0; /* just for the compiler */
        ipl=0; /* just for the compiler */
        for ( i=0 ; i<RTAX_MAX ; i++ )
        { if ( ifamaddr & (1<<i) )
          { /* we are only interested by NETMASK and IFA */
            if ( i==RTAX_NETMASK || i==RTAX_IFA )
            { psai=(struct sockaddr_in *)psa;
              if ( i==RTAX_NETMASK )
	      { netmask=lcrzo_ntohl(psai->sin_addr.s_addr);
	        netmaskset=LCRZO_TRUE;
              }
              else if ( i==RTAX_IFA )
              { ipl=lcrzo_ntohl(psai->sin_addr.s_addr);
	        iplset=LCRZO_TRUE;
              }
            }
            /* psa points to the next item */
            psa=(struct sockaddr *)(((char *)psa) + FB_ROUNDUP(psa->sa_len));
          }
        }
        /* we add the device */
        if ( netmaskset && iplset )
        { lcrzo_priv_conf_devices_add_system(device, etha, ipl, netmask, mtu,
          isup, isanalias);
	  isanalias=LCRZO_TRUE;
        }
      }
    }
  }

  lcrzo_string_free(buf);
  return(LCRZO_ERR_OK);
}
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
#elif defined LCRZODEF_SYSTEM_Windows
{ int ret;
  lcrzo_priv_globalvars *ptrglo;

  lcrzo_er(lcrzo_priv_globalvars_ptr_get(&ptrglo));
  switch(ptrglo->windows_systemversion)
  { case LCRZO_WINDOWS_SYSTEMVERSION_nt4:
    case LCRZO_WINDOWS_SYSTEMVERSION_2k:
    case LCRZO_WINDOWS_SYSTEMVERSION_xp:
      ret=lcrzo_priv_conf_init_dev_iphlpapidll();
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_snmpdll();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_NTregistery();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_packetdll();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_gethostbyname();
      }
      break;

    case LCRZO_WINDOWS_SYSTEMVERSION_95:
      ret=lcrzo_priv_conf_init_dev_snmpdll();
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_W9xregistery();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_gethostbyname();
      }
      if (ret!=LCRZO_ERR_OK)
      { /* this function doesn't work correctly */
        ret=lcrzo_priv_conf_init_dev_packetdll();
      }
      break;

    case LCRZO_WINDOWS_SYSTEMVERSION_98:
    case LCRZO_WINDOWS_SYSTEMVERSION_me:
      ret=lcrzo_priv_conf_init_dev_iphlpapidll();
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_snmpdll();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_W9xregistery();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_gethostbyname();
      }
      if (ret!=LCRZO_ERR_OK)
      { /* this function doesn't work correctly */
        ret=lcrzo_priv_conf_init_dev_packetdll();
      }
      break;

    default:
      ret=lcrzo_priv_conf_init_dev_iphlpapidll();
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_snmpdll();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_NTregistery();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_W9xregistery();
      }
      if (ret!=LCRZO_ERR_OK)
      { ret=lcrzo_priv_conf_init_dev_gethostbyname();
      }
      if (ret!=LCRZO_ERR_OK)
      { /* this function doesn't work correctly */
        ret=lcrzo_priv_conf_init_dev_packetdll();
      }
      break;
  }

  /* return OK even if nothing was initialized */
  return(LCRZO_ERR_OK);
}
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif

/*-------------------------------------------------------------*/
int lcrzo_priv_conf_dev_debug_fprint(LCRZOFILE *pf)
#ifdef LCRZODEF_SYSTEM_Unix
{ return(LCRZO_ERR_OK);
  pf=pf;
}
#elif defined LCRZODEF_SYSTEM_Windows
{ 
  fprintf(pf, "\n\n++++++++++++++++++++++++++++++++\n");
  fprintf(pf, "Configuration obtained with lcrzo_priv_conf_init_dev_iphlpapidll\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_dev_iphlpapidll());
  lcrzo_conf_fprint(pf);
  lcrzo_priv_conf_device_init_ipl_debug_fprint(pf);
  lcrzo_priv_conf_etha_init_device_debug_fprint(pf);
  lcrzo_priv_conf_devicenumbername_debug_fprint(pf);

  fprintf(pf, "\n\n++++++++++++++++++++++++++++++++\n");
  fprintf(pf, "Configuration obtained with lcrzo_priv_conf_init_dev_snmpdll\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_dev_snmpdll());
  lcrzo_conf_fprint(pf);
  lcrzo_priv_conf_device_init_ipl_debug_fprint(pf);
  lcrzo_priv_conf_etha_init_device_debug_fprint(pf);
  lcrzo_priv_conf_devicenumbername_debug_fprint(pf);

  fprintf(pf, "\n\n++++++++++++++++++++++++++++++++\n");
  fprintf(pf, "Configuration obtained with lcrzo_priv_conf_init_dev_NTregistery\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_dev_NTregistery());
  lcrzo_conf_fprint(pf);
  lcrzo_priv_conf_device_init_ipl_debug_fprint(pf);
  lcrzo_priv_conf_etha_init_device_debug_fprint(pf);

  fprintf(pf, "\n\n++++++++++++++++++++++++++++++++\n");
  fprintf(pf, "Configuration obtained with lcrzo_priv_conf_init_dev_W9xregistery\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_dev_W9xregistery());
  lcrzo_conf_fprint(pf);
  lcrzo_priv_conf_device_init_ipl_debug_fprint(pf);
  lcrzo_priv_conf_etha_init_device_debug_fprint(pf);

  fprintf(pf, "\n\n++++++++++++++++++++++++++++++++\n");
  fprintf(pf, "Configuration obtained with lcrzo_priv_conf_init_dev_packetdll\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_dev_packetdll());
  lcrzo_conf_fprint(pf);
  lcrzo_priv_conf_device_init_ipl_debug_fprint(pf);
  lcrzo_priv_conf_etha_init_device_debug_fprint(pf);

  fprintf(pf, "\n\n++++++++++++++++++++++++++++++++\n");
  fprintf(pf, "Configuration obtained with lcrzo_priv_conf_init_dev_gethostbyname\n");
  lcrzo_conf_flush_system();
  lcrzo_err_fprint(pf, lcrzo_priv_conf_init_dev_gethostbyname());
  lcrzo_conf_fprint(pf);
  lcrzo_priv_conf_device_init_ipl_debug_fprint(pf);
  lcrzo_priv_conf_etha_init_device_debug_fprint(pf);

  return(LCRZO_ERR_OK);
}
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif
