Agrego cliente busybox udhcpc y comandos del manager.

master
Félix Arreola Rodríguez 2022-01-02 13:54:25 -06:00
parent f048dde998
commit 072b89bd62
6 changed files with 351 additions and 28 deletions

View File

@ -45,6 +45,10 @@
#define INFINITY_LIFE_TIME 0xFFFFFFFFU
#endif
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
typedef struct _NetworkInadorHandle NetworkInadorHandle;
typedef struct _NetworkInadorManager NetworkInadorManager;
typedef struct _Interface Interface;
@ -117,7 +121,8 @@ typedef struct _WirelessInfo {
/* Información del proceso de DHCP */
enum {
IFACE_NO_DHCP = 0,
IFACE_ISC_DHCLIENT
IFACE_ISC_DHCLIENT,
IFACE_BUSYBOX_UDHCPC
};
/* FIXME: Revisar estos estados */
@ -150,6 +155,7 @@ typedef struct _InterfaceDHCPClientInfo {
int prefix;
struct_addr dhcp_server_ip;
uint32_t lease_time;
/* TODO: Falta almacenar la información de DNS */
} InterfaceDHCPClientInfo;

View File

@ -41,7 +41,7 @@ void interfaces_dhcp_client_ignore_kill (GPid pid, gint status, gpointer data) {
g_spawn_check_exit_status (status, NULL);
}
void interfaces_dhcp_prepare_args_for_dhclient (char **argv, int size, char *iface_name, char *pid_file, size_t pid_file_len) {
void interfaces_dhcp_prepare_args_for_isc_dhclient (char **argv, int size, char *iface_name, char *pid_file, size_t pid_file_len) {
snprintf (pid_file, pid_file_len, "/run/dhclient-%s.pid", iface_name);
/* Preparar los argumentos para el proceso */
@ -56,6 +56,22 @@ void interfaces_dhcp_prepare_args_for_dhclient (char **argv, int size, char *ifa
argv[8] = NULL;
}
void interfaces_dhcp_prepare_args_for_busybox_udhcpc (char **argv, int size, char *iface_name, char *pid_file, size_t pid_file_len) {
snprintf (pid_file, pid_file_len, "/run/dhclient-%s.pid", iface_name);
/* Preparar los argumentos para el proceso */
argv[0] = "/bin/busybox";
argv[1] = "udhcpc";
argv[2] = "-i";
argv[3] = iface_name;
argv[4] = "-p";
argv[5] = pid_file;
argv[6] = "-s";
argv[7] = "/home/gatuno/Proyectos/NetworkInador/src/ni-dhcp-helper";
argv[8] = "-f";
argv[9] = NULL;
}
void interfaces_dhcp_client_killed_cb (GPid pid, gint status, gpointer data) {
Interface *iface = (Interface *) data;
gboolean ret;
@ -64,13 +80,17 @@ void interfaces_dhcp_client_killed_cb (GPid pid, gint status, gpointer data) {
gchar pid_file[256];
/* Preparar los argumentos */
interfaces_dhcp_prepare_args_for_dhclient (argv, 20, iface->name, pid_file, sizeof (pid_file));
if (iface->dhcpc.type == IFACE_ISC_DHCLIENT) {
interfaces_dhcp_prepare_args_for_isc_dhclient (argv, 20, iface->name, pid_file, sizeof (pid_file));
} else if (iface->dhcpc.type == IFACE_BUSYBOX_UDHCPC) {
interfaces_dhcp_prepare_args_for_busybox_udhcpc (argv, 20, iface->name, pid_file, sizeof (pid_file));
}
if (g_spawn_check_exit_status (status, NULL)) {
/* Revisar si necesito algo */
}
if (iface->dhcpc.type == IFACE_ISC_DHCLIENT) {
if (iface->dhcpc.type == IFACE_ISC_DHCLIENT || iface->dhcpc.type == IFACE_BUSYBOX_UDHCPC) {
if (iface->dhcpc.flags & DHCP_CLIENT_FLAG_AUTO_RESTART) {
/* Se cerró o mataron el proceso, reiniciar */
ret = g_spawn_async_with_pipes (
@ -105,6 +125,17 @@ void interfaces_dhcp_client_killed_cb (GPid pid, gint status, gpointer data) {
}
}
static void interfaces_dhcp_clear_info (InterfaceDHCPClientInfo *dhcpc) {
memset (&dhcpc->ip, 0, sizeof (dhcpc->ip));
memset (&dhcpc->gateway, 0, sizeof (dhcpc->gateway));
memset (&dhcpc->broadcast, 0, sizeof (dhcpc->broadcast));
memset (&dhcpc->dhcp_server_ip, 0, sizeof (dhcpc->dhcp_server_ip));
dhcpc->lease_time = 0;
dhcpc->prefix = 0;
/* TODO: Borrar la información de DNS */
}
int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type, uint32_t flags) {
/* IFNAMSIZ */
Interface *iface;
@ -122,18 +153,23 @@ int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type
}
/* Preparar los argumentos */
interfaces_dhcp_prepare_args_for_dhclient (argv, 20, iface->name, pid_file, sizeof (pid_file));
if (type == IFACE_ISC_DHCLIENT) {
interfaces_dhcp_prepare_args_for_isc_dhclient (argv, 20, iface->name, pid_file, sizeof (pid_file));
} else if (type == IFACE_BUSYBOX_UDHCPC) {
interfaces_dhcp_prepare_args_for_busybox_udhcpc (argv, 20, iface->name, pid_file, sizeof (pid_file));
}
if (iface->dhcpc.type != IFACE_NO_DHCP) {
/* No puedo correr otro tipo de DHCP */
return -1;
}
if (iface->dhcpc.type == IFACE_ISC_DHCLIENT && iface->dhcpc.dhcp_state != DHCP_CLIENT_KILLED) {
if ((iface->dhcpc.type == IFACE_ISC_DHCLIENT || iface->dhcpc.type == IFACE_BUSYBOX_UDHCPC) && iface->dhcpc.dhcp_state != DHCP_CLIENT_KILLED) {
/* El cliente de dhcp ya está corriendo, no hacer nada */
return -1;
}
interfaces_dhcp_clear_info (&iface->dhcpc);
ret = g_spawn_async_with_pipes (
"/",
argv,
@ -157,7 +193,7 @@ int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type
}
iface->dhcpc.dhcp_state = DHCP_CLIENT_EXTERNAL_RUNNING;
iface->dhcpc.type = IFACE_ISC_DHCLIENT;
iface->dhcpc.type = type;
iface->dhcpc.flags = flags;
iface->dhcpc.process_watch = g_child_watch_add (iface->dhcpc.process_pid, interfaces_dhcp_client_killed_cb, iface);
@ -165,7 +201,7 @@ int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type
return 0;
}
void interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index) {
int interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index) {
Interface *iface;
iface = _interfaces_locate_by_index (handle->interfaces, index);
@ -173,18 +209,18 @@ void interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index) {
if (iface == NULL) {
printf ("Error, solicitaron operación sobre interfaz que no existe\n");
return;
return -1;
}
if (iface->dhcpc.type == IFACE_NO_DHCP) {
return;
return -1;
}
if (iface->dhcpc.type == IFACE_ISC_DHCLIENT) {
if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) return;
if (iface->dhcpc.type == IFACE_ISC_DHCLIENT || iface->dhcpc.type == IFACE_BUSYBOX_UDHCPC) {
if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) return -1;
/* Proceso, matar y reiniciar estado */
iface->dhcpc.type = IFACE_NO_DHCP;
iface->dhcpc.flags &= (~DHCP_CLIENT_FLAG_AUTO_RESTART);
g_source_remove (iface->dhcpc.process_watch);
@ -192,7 +228,15 @@ void interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index) {
g_child_watch_add (iface->dhcpc.process_pid, interfaces_dhcp_client_ignore_kill, NULL);
kill (iface->dhcpc.process_pid, SIGTERM);
iface->dhcpc.type = IFACE_NO_DHCP;
/* TODO: Revisar aquí si es pertinente desconfigurar la interfaz y borrar la información obtenida */
interfaces_dhcp_clear_info (&iface->dhcpc);
/* TODO: Enviar actualización de estado aquí */
}
return 0;
}
void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *handle, int index, int status, struct_addr *ip, int prefix, struct_addr *gateway, struct_addr *broadcast, struct_addr *dhcp_server, uint32_t lease_time, struct_addr *dns_list, int dns_count, char *domain_name) {
@ -211,7 +255,8 @@ void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *hand
return;
}
if (iface->dhcpc.type == IFACE_ISC_DHCLIENT) {
// TODO: Cuando entre a estado Selecting, previo otro estado diferente, borrar la IP, si es que tenemos
if (iface->dhcpc.type == IFACE_ISC_DHCLIENT || iface->dhcpc.type == IFACE_BUSYBOX_UDHCPC) {
/* Un proceso muerto no puede informar de cambios de estados */
if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) return;
@ -248,6 +293,7 @@ void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *hand
memcpy (&iface->dhcpc.broadcast, broadcast, sizeof (iface->dhcpc.broadcast));
memcpy (&iface->dhcpc.dhcp_server_ip, dhcp_server, sizeof (iface->dhcpc.dhcp_server_ip));
iface->dhcpc.lease_time = lease_time;
char buf_a[256], buf_b[256], buf_c[256], buf_d[256];
inet_ntop (AF_INET, &iface->dhcpc.ip, buf_a, sizeof (buf_a));

View File

@ -26,7 +26,7 @@
#include "common.h"
int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type, uint32_t flags);
void interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index);
int interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index);
void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *handle, int index, int status, struct_addr *ip, int prefix, struct_addr *gateway, struct_addr *broadcast, struct_addr *dhcp_server, uint32_t lease_time, struct_addr *dns_list, int dns_count, char *domain_name);
#endif /* __DHCP_CLIENT_H__ */

View File

@ -46,6 +46,8 @@
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
void _manager_send_dhcp_status (ManagerClientInfo *manager_client, InterfaceDHCPClientInfo *dhcpc, gboolean is_event);
static void _manager_send_error (ManagerClientInfo *manager_client, int error, int orig_cmd) {
unsigned char buffer[8];
@ -732,7 +734,7 @@ static void _manager_execute_dhcp_client_feed (ManagerClientInfo *manager_client
return;
}
if (iface->dhcpc.type != IFACE_ISC_DHCLIENT) {
if (iface->dhcpc.type != IFACE_ISC_DHCLIENT && iface->dhcpc.type != IFACE_BUSYBOX_UDHCPC) {
_manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_DHCP_CLIENT_FEED);
return;
}
@ -807,6 +809,183 @@ static void _manager_execute_dhcp_client_feed (ManagerClientInfo *manager_client
_manager_send_executed (manager_client);
}
static void _manager_execute_dhcp_run (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) {
Interface *iface;
int ret;
int family, tipo;
uint32_t flags;
if (buffer_len < 12) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RUN_DHCP);
return;
}
family = buffer[6];
//if (family != AF_INET && family != AF_INET6) {
if (family != AF_INET) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_RUN_DHCP);
return;
}
iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_RUN_DHCP);
if (iface == NULL) return;
tipo = buffer[7];
if (tipo == 1) {
tipo = IFACE_ISC_DHCLIENT;
} else if (tipo == 2) {
tipo = IFACE_BUSYBOX_UDHCPC;
} else {
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_RUN_DHCP);
return;
}
/* TODO: Revisar las banderas */
memcpy (&flags, &buffer[8], 4);
ret = interfaces_dhcp_client_run (manager_client->manager->handle, iface->index, tipo, flags);
if (ret == 0) {
/* OK */
_manager_send_executed (manager_client);
} else {
_manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_RUN_DHCP);
}
}
static void _manager_execute_dhcp_stop (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) {
Interface *iface;
int ret;
int family;
if (buffer_len < 7) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_STOP_DHCP);
return;
}
family = buffer[6];
//if (family != AF_INET && family != AF_INET6) {
if (family != AF_INET) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_STOP_DHCP);
return;
}
iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_STOP_DHCP);
if (iface == NULL) return;
ret = interfaces_dhcp_client_stop (manager_client->manager->handle, iface->index);
if (ret == 0) {
/* OK */
_manager_send_executed (manager_client);
} else {
_manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_STOP_DHCP);
}
}
static void _manager_execute_dhcp_get_status (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) {
Interface *iface;
int family;
if (buffer_len < 7) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_GET_DHCP_STATUS);
return;
}
family = buffer[6];
//if (family != AF_INET && family != AF_INET6) {
if (family != AF_INET) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_GET_DHCP_STATUS);
return;
}
iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_GET_DHCP_STATUS);
if (iface == NULL) return;
_manager_send_dhcp_status (manager_client, &iface->dhcpc, FALSE);
}
void _manager_send_dhcp_status (ManagerClientInfo *manager_client, InterfaceDHCPClientInfo *dhcpc, gboolean is_event) {
Interface *iface;
unsigned char buffer[80];
int family_size = 0;
int label_len;
int pos;
int family = AF_INET;
struct in_addr empty;
memset (&empty, 0, sizeof (empty));
iface = container_of (dhcpc, Interface, dhcpc);
if (is_event) {
buffer[0] = NET_INADOR_TYPE_EVENT;
buffer[1] = NET_INADOR_EVENT_DHCP_STATUS;
} else {
buffer[0] = NET_INADOR_TYPE_RESPONSE;
buffer[1] = NET_INADOR_RESPONSE_DHCP_STATUS;
}
/* Familia */
if (family == AF_INET) {
family_size = sizeof (struct in_addr);
}
memcpy (&buffer[2], &iface->index, 4);
buffer[6] = family;
buffer[7] = dhcpc->type;
buffer[8] = dhcpc->dhcp_state;
/* Prefijo */
buffer[9] = dhcpc->prefix;
/* Los campos de bits */
buffer[10] = 0;
if (memcmp (&dhcpc->gateway, &empty, 4) == 0) {
buffer[10] |= 0x01;
}
if (memcmp (&dhcpc->broadcast, &empty, 4) == 0) {
buffer[10] |= 0x02;
}
if (memcmp (&dhcpc->dhcp_server_ip, &empty, 4) == 0) {
buffer[10] |= 0x04;
}
/* TODO: Falta enviar la información de cantidad de servidores DNS */
buffer[11] = 0;
memcpy (&buffer[12], &dhcpc->lease_time, 4);
/* La dirección principal */
memcpy (&buffer[16], &dhcpc->ip, family_size);
pos = 16 + family_size;
if (memcmp (&dhcpc->gateway, &empty, 4) != 0) {
memcpy (&buffer[pos], &dhcpc->gateway, family_size);
pos += family_size;
}
if (memcmp (&dhcpc->broadcast, &empty, 4) != 0) {
memcpy (&buffer[pos], &dhcpc->broadcast, family_size);
pos += family_size;
}
if (memcmp (&dhcpc->dhcp_server_ip, &empty, 4) != 0) {
memcpy (&buffer[pos], &dhcpc->dhcp_server_ip, family_size);
pos += family_size;
}
/* TODO: Falta aquí enviar la lista de servidores DNS y el domain name */
send (manager_client->fd, buffer, pos, 0);
}
static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition, gpointer data) {
ManagerClientInfo *manager_client = (ManagerClientInfo *) data;
NetworkInadorManager *manager = manager_client->manager;
@ -896,6 +1075,15 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition
case NET_INADOR_COMMAND_DHCP_CLIENT_FEED:
_manager_execute_dhcp_client_feed (manager_client, buffer, bytes);
break;
case NET_INADOR_COMMAND_RUN_DHCP:
_manager_execute_dhcp_run (manager_client, buffer, bytes);
break;
case NET_INADOR_COMMAND_STOP_DHCP:
_manager_execute_dhcp_stop (manager_client, buffer, bytes);
break;
case NET_INADOR_COMMAND_GET_DHCP_STATUS:
_manager_execute_dhcp_get_status (manager_client, buffer, bytes);
break;
default:
_manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command);
}

View File

@ -12,6 +12,7 @@ enum {
/* Lista de eventos */
#define NET_INADOR_EVENT_MASK_INTERFACES 0x01
#define NET_INADOR_EVENT_MASK_IP 0x02
#define NET_INADOR_EVENT_MASK_DHCP_STATUS 0x04
enum {
NET_INADOR_COMMAND_LIST_IFACES = 1,
@ -34,6 +35,10 @@ enum {
NET_INADOR_COMMAND_ADD_IP,
NET_INADOR_COMMAND_REMOVE_IP,
NET_INADOR_COMMAND_RUN_DHCP = 48,
NET_INADOR_COMMAND_STOP_DHCP,
NET_INADOR_COMMAND_GET_DHCP_STATUS,
NET_INADOR_COMMAND_SET_EVENT_MASK = 192,
/* Los siguientes comandos son para uso interno */
@ -56,7 +61,9 @@ enum {
NET_INADOR_EVENT_IFACE_ADDED = 2,
NET_INADOR_EVENT_IPADDR_ADDED,
NET_INADOR_EVENT_IFACE_REMOVED,
NET_INADOR_EVENT_IPADDR_REMOVED
NET_INADOR_EVENT_IPADDR_REMOVED,
NET_INADOR_EVENT_DHCP_STATUS = 6
};
enum {
@ -64,6 +71,8 @@ enum {
NET_INADOR_RESPONSE_IFACE = 2,
NET_INADOR_RESPONSE_IPADDR,
NET_INADOR_RESPONSE_DHCP_STATUS = 6
};
enum {

View File

@ -274,17 +274,77 @@ int parse_int (char *var, int *entero) {
return 0;
}
enum {
IFACE_ISC_DHCLIENT = 1,
IFACE_BUSYBOX_UDHCPC
};
const char *isc_dhcp_reasons[] = {
"MEDIUM",
"PREINIT",
"BOUND",
"RENEW",
"REBIND",
"REBOOT",
"EXPIRE",
"FAIL",
"STOP",
"RELEASE",
"NBI",
"TIMEOUT",
NULL
};
const char *busybox_dhcp_argv[] = {
"deconfig",
"bound",
"renew",
"nak"
};
int main (int argc, char *argv[]) {
char *reason, *interface;
int s, ret;
int s, ret, tipo;
struct sockaddr_un path_dest;
struct in_addr ip, netmask, gateway, broadcast, dhcp_server;
int prefix, lease_time;
debug (argc, argv);
tipo = 0;
/* Tratar de determinar si estamos siendo corridos por un el DHCP del ISC o por el udhcpc busybox */
reason = getenv ("reason");
if (reason != NULL) {
s = 0;
while (isc_dhcp_reasons[s] != NULL) {
if (strcmp (reason, isc_dhcp_reasons[s]) == 0) {
/* Es un ISC DHCP Client */
tipo = IFACE_ISC_DHCLIENT;
break;
}
s++;
}
}
if (tipo == 0 && argc > 1) {
/* Intentar revisar si es un busybox udhcpc */
s = 0;
while (busybox_dhcp_argv[s] != NULL) {
if (strcmp (argv[1], busybox_dhcp_argv[s]) == 0) {
tipo = IFACE_BUSYBOX_UDHCPC;
reason = argv[1];
break;
}
s++;
}
}
if (tipo == 0) {
return 1;
}
interface = getenv ("interface");
if (reason == NULL || interface == NULL) {
@ -308,12 +368,15 @@ int main (int argc, char *argv[]) {
return 1;
}
if (strcmp (reason, "PREINIT") == 0) {
if (strcmp (reason, "PREINIT") == 0 || // ISC DHCP
strcmp (reason, "deconfig") == 0 // Busybox udhcpc
) {
send_preinit (s, interface);
} if (strcmp (reason, "FAIL") == 0) {
} else if (strcmp (reason, "BOUND") == 0 || strcmp (reason, "REBOOT") == 0 ||
strcmp (reason, "RENEW") == 0 || strcmp (reason, "REBIND") == 0
strcmp (reason, "RENEW") == 0 || strcmp (reason, "REBIND") == 0 || // 4 de ISC DHCP
strcmp (reason, "bound") == 0 || strcmp (reason, "renew") == 0 // 2 de Busybox udhcpc
) {
/*
* Los valores más importantes recibidos:
@ -328,12 +391,21 @@ int main (int argc, char *argv[]) {
*/
/* Parsear y revisar las direcciones IP recibidas */
char *s_ip, *s_mask, *s_gateway, *s_broadcast, *s_lease_time, *s_dhcp_server;
if (tipo == IFACE_ISC_DHCLIENT) {
s_ip = getenv ("new_ip_address");
s_mask = getenv ("new_subnet_mask");
s_gateway = getenv ("new_routers");
s_broadcast = getenv ("new_broadcast_address");
s_lease_time = getenv ("new_dhcp_lease_time");
s_dhcp_server = getenv ("new_dhcp_server_identifier");
} else if (tipo == IFACE_BUSYBOX_UDHCPC) {
s_ip = getenv ("ip");
s_mask = getenv ("subnet");
s_gateway = getenv ("router");
s_broadcast = getenv ("broadcast");
s_lease_time = getenv ("lease");
s_dhcp_server = getenv ("serverid");
}
/* TODO: Faltan los DNS */
if (parse_ip (s_ip, &ip) < 0) {
@ -364,7 +436,9 @@ int main (int argc, char *argv[]) {
}
int is_bound = 0;
if (strcmp (reason, "BOUND") == 0 || strcmp (reason, "REBOOT") == 0) {
if (strcmp (reason, "BOUND") == 0 || strcmp (reason, "REBOOT") == 0 || // Del ISC dhcp
strcmp (reason, "bound") == 0 // del busybox
) {
is_bound = 1;
}
send_bound_renew (s, is_bound, interface, &ip, prefix, &gateway, &broadcast, &dhcp_server, lease_time);