Agrego rutas en el network-inador.
parent
dfc2abecd1
commit
d1a75017b6
|
@ -9,6 +9,7 @@ network_inador_SOURCES = main.c \
|
||||||
bridge.c bridge.h \
|
bridge.c bridge.h \
|
||||||
manager.c manager.h \
|
manager.c manager.h \
|
||||||
dhcp_client.c dhcp_client.h \
|
dhcp_client.c dhcp_client.h \
|
||||||
|
routes.c routes.h \
|
||||||
wireless_if.c wireless_if.h \
|
wireless_if.c wireless_if.h \
|
||||||
wireless_bss.c wireless_bss.h
|
wireless_bss.c wireless_bss.h
|
||||||
|
|
||||||
|
|
42
src/common.h
42
src/common.h
|
@ -61,7 +61,7 @@ typedef union {
|
||||||
typedef struct _IPAddr {
|
typedef struct _IPAddr {
|
||||||
sa_family_t family;
|
sa_family_t family;
|
||||||
|
|
||||||
int prefix;
|
uint8_t prefix;
|
||||||
struct_addr local_addr;
|
struct_addr local_addr;
|
||||||
struct_addr addr;
|
struct_addr addr;
|
||||||
struct_addr brd_addr;
|
struct_addr brd_addr;
|
||||||
|
@ -69,12 +69,12 @@ typedef struct _IPAddr {
|
||||||
char label[256];
|
char label[256];
|
||||||
struct ifa_cacheinfo cacheinfo;
|
struct ifa_cacheinfo cacheinfo;
|
||||||
|
|
||||||
int is_p2p;
|
uint8_t is_p2p;
|
||||||
int has_brd;
|
uint8_t has_brd;
|
||||||
int has_local;
|
uint8_t has_local;
|
||||||
|
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
unsigned char scope;
|
uint8_t scope;
|
||||||
|
|
||||||
Interface *iface;
|
Interface *iface;
|
||||||
} IPAddr;
|
} IPAddr;
|
||||||
|
@ -158,8 +158,6 @@ typedef struct _InterfaceDHCPClientInfo {
|
||||||
|
|
||||||
struct_addr dhcp_server_ip;
|
struct_addr dhcp_server_ip;
|
||||||
uint32_t lease_time;
|
uint32_t lease_time;
|
||||||
|
|
||||||
/* TODO: Falta almacenar la información de DNS */
|
|
||||||
} InterfaceDHCPClientInfo;
|
} InterfaceDHCPClientInfo;
|
||||||
|
|
||||||
struct _Interface {
|
struct _Interface {
|
||||||
|
@ -220,9 +218,37 @@ typedef struct _netlink_event_pair {
|
||||||
guint source;
|
guint source;
|
||||||
} NetlinkEventPair;
|
} NetlinkEventPair;
|
||||||
|
|
||||||
|
typedef struct _RouteNH {
|
||||||
|
struct_addr gw;
|
||||||
|
uint32_t out_index;
|
||||||
|
uint8_t nh_weight;
|
||||||
|
uint8_t nh_flags;
|
||||||
|
} RouteNH;
|
||||||
|
|
||||||
|
/* La tabla de ruteo */
|
||||||
|
typedef struct _Route {
|
||||||
|
sa_family_t family; /* AF_INET, AF_INET6 */
|
||||||
|
|
||||||
|
uint8_t type; /* Unicast, local, broadcast, etc... */
|
||||||
|
uint32_t table;
|
||||||
|
struct_addr dest;
|
||||||
|
uint8_t prefix;
|
||||||
|
|
||||||
|
uint8_t protocol;
|
||||||
|
uint8_t tos;
|
||||||
|
uint8_t scope;
|
||||||
|
|
||||||
|
struct_addr prefsrc;
|
||||||
|
uint32_t priority;
|
||||||
|
|
||||||
|
/* Los brincos */
|
||||||
|
GList *nexthops;
|
||||||
|
} Route;
|
||||||
|
|
||||||
struct _NetworkInadorHandle {
|
struct _NetworkInadorHandle {
|
||||||
GList *interfaces;
|
GList *interfaces;
|
||||||
//Routev4 *rtable_v4;
|
GList *route_v4_tables;
|
||||||
|
GList *route_v6_tables;
|
||||||
|
|
||||||
NetworkInadorManager *manager;
|
NetworkInadorManager *manager;
|
||||||
|
|
||||||
|
|
|
@ -643,3 +643,18 @@ void interfaces_init (NetworkInadorHandle *handle) {
|
||||||
ip_address_init (handle);
|
ip_address_init (handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void interfaces_clean_up (NetworkInadorHandle *handle) {
|
||||||
|
GList *g;
|
||||||
|
Interface *iface;
|
||||||
|
|
||||||
|
for (g = handle->interfaces; g != NULL; g = g->next) {
|
||||||
|
iface = (Interface *) g->data;
|
||||||
|
/* Antes de eliminar la interfaz, eliminar la lista ligada de todas las direcciones IP */
|
||||||
|
g_list_free_full (iface->address, free);
|
||||||
|
|
||||||
|
iface->address = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (handle->interfaces, free);
|
||||||
|
handle->interfaces = NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -44,5 +44,7 @@ int interfaces_change_set_up (NetworkInadorHandle *handle, int index);
|
||||||
int interfaces_change_set_down (NetworkInadorHandle *handle, int index);
|
int interfaces_change_set_down (NetworkInadorHandle *handle, int index);
|
||||||
int interfaces_change_name (NetworkInadorHandle *handle, int index, char * new_name);
|
int interfaces_change_name (NetworkInadorHandle *handle, int index, char * new_name);
|
||||||
|
|
||||||
|
void interfaces_clean_up (NetworkInadorHandle *handle);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
10
src/main.c
10
src/main.c
|
@ -45,6 +45,7 @@
|
||||||
#include "ip-address.h"
|
#include "ip-address.h"
|
||||||
#include "bridge.h"
|
#include "bridge.h"
|
||||||
#include "dhcp_client.h"
|
#include "dhcp_client.h"
|
||||||
|
#include "routes.h"
|
||||||
|
|
||||||
/* Usados para salir en caso de una señal */
|
/* Usados para salir en caso de una señal */
|
||||||
static int sigterm_pipe_fds[2] = { -1, -1 };
|
static int sigterm_pipe_fds[2] = { -1, -1 };
|
||||||
|
@ -70,6 +71,8 @@ static void _sigterm_handler (int signum) {
|
||||||
static gboolean _main_quit_handler (GIOChannel *source, GIOCondition cond, gpointer data) {
|
static gboolean _main_quit_handler (GIOChannel *source, GIOCondition cond, gpointer data) {
|
||||||
GMainLoop *loop = (GMainLoop *) data;
|
GMainLoop *loop = (GMainLoop *) data;
|
||||||
g_main_loop_quit (loop);
|
g_main_loop_quit (loop);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _main_setup_signal (void *loop) {
|
static void _main_setup_signal (void *loop) {
|
||||||
|
@ -104,6 +107,7 @@ static void _main_setup_signal (void *loop) {
|
||||||
g_io_channel_set_close_on_unref (io, TRUE);
|
g_io_channel_set_close_on_unref (io, TRUE);
|
||||||
|
|
||||||
g_io_add_watch (io, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR, _main_quit_handler, loop);
|
g_io_add_watch (io, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR, _main_quit_handler, loop);
|
||||||
|
g_io_channel_unref (io);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,8 +140,12 @@ int main (int argc, char *argv[]) {
|
||||||
|
|
||||||
_main_setup_signal (loop);
|
_main_setup_signal (loop);
|
||||||
|
|
||||||
|
/* Inicializar las interfaces (y las direcciones IP) */
|
||||||
interfaces_init (&handle);
|
interfaces_init (&handle);
|
||||||
|
|
||||||
|
/* Inicializar las rutas */
|
||||||
|
routes_init (&handle);
|
||||||
|
|
||||||
manager_init (&handle);
|
manager_init (&handle);
|
||||||
|
|
||||||
g_main_loop_run (loop);
|
g_main_loop_run (loop);
|
||||||
|
@ -145,6 +153,8 @@ int main (int argc, char *argv[]) {
|
||||||
/* Detener la llegada de eventos */
|
/* Detener la llegada de eventos */
|
||||||
netlink_events_clear (&handle);
|
netlink_events_clear (&handle);
|
||||||
|
|
||||||
|
routes_clean_up (&handle);
|
||||||
|
interfaces_clean_up (&handle);
|
||||||
// nl_socket_free???
|
// nl_socket_free???
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
199
src/manager.c
199
src/manager.c
|
@ -1004,6 +1004,160 @@ void _manager_send_dhcp_status (ManagerClientInfo *manager_client, InterfaceDHCP
|
||||||
send (manager_client->fd, buffer, pos, 0);
|
send (manager_client->fd, buffer, pos, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _manager_send_route (ManagerClientInfo *manager_client, Route *route, gboolean is_event) {
|
||||||
|
unsigned char buffer[80];
|
||||||
|
int family_size = 0;
|
||||||
|
int pos, has_gw;
|
||||||
|
struct_addr empty;
|
||||||
|
GList *g;
|
||||||
|
RouteNH *nexthop;
|
||||||
|
|
||||||
|
memset (&empty, 0, sizeof (empty));
|
||||||
|
|
||||||
|
if (is_event) {
|
||||||
|
buffer[0] = NET_INADOR_TYPE_EVENT;
|
||||||
|
buffer[1] = NET_INADOR_EVENT_ROUTE_ADDED;
|
||||||
|
} else {
|
||||||
|
buffer[0] = NET_INADOR_TYPE_RESPONSE;
|
||||||
|
buffer[1] = NET_INADOR_RESPONSE_ROUTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Familia y máscara */
|
||||||
|
if (route->family == AF_INET) {
|
||||||
|
family_size = sizeof (struct in_addr);
|
||||||
|
} else if (route->family == AF_INET6) {
|
||||||
|
family_size = sizeof (struct in6_addr);
|
||||||
|
}
|
||||||
|
buffer[2] = route->family;
|
||||||
|
buffer[3] = route->type;
|
||||||
|
memcpy (&buffer[4], &route->table, 4);
|
||||||
|
buffer[8] = route->prefix;
|
||||||
|
buffer[9] = route->protocol;
|
||||||
|
buffer[10] = route->tos;
|
||||||
|
buffer[11] = route->scope;
|
||||||
|
buffer[12] = 0;
|
||||||
|
if (memcmp (&empty, &route->prefsrc, family_size) != 0) {
|
||||||
|
/* Tiene pref-src */
|
||||||
|
buffer[12] |= 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[13] = 0; /* Los next-hop se incrementarán conforme los recorra */
|
||||||
|
memcpy (&buffer[14], &route->priority, 4);
|
||||||
|
|
||||||
|
/* Copiar la Ruta de destino */
|
||||||
|
memcpy (&buffer[18], &route->dest, family_size);
|
||||||
|
pos = 18 + family_size;
|
||||||
|
|
||||||
|
/* Copiar el pref-src, si lo tiene */
|
||||||
|
if (buffer[12] & 0x01) {
|
||||||
|
memcpy (&buffer[pos], &route->prefsrc, family_size);
|
||||||
|
pos += family_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Recorrer todos los nexthops */
|
||||||
|
g = route->nexthops;
|
||||||
|
while (g != NULL) {
|
||||||
|
nexthop = (RouteNH *) g->data;
|
||||||
|
|
||||||
|
buffer[pos] = 0;
|
||||||
|
has_gw = 0;
|
||||||
|
if (memcmp (&nexthop->gw, &empty, family_size) != 0) {
|
||||||
|
has_gw = 1;
|
||||||
|
buffer[pos] |= 0x01;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
buffer[pos++] = nexthop->nh_flags; /* Flags next-hop */
|
||||||
|
buffer[pos++] = nexthop->nh_weight; /* Weight next-hop */
|
||||||
|
|
||||||
|
buffer[pos++] = 0; /* Omitimos un byte faltante */
|
||||||
|
|
||||||
|
/* La interfaz de salida */
|
||||||
|
memcpy (&buffer[pos], &nexthop->out_index, 4);
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
if (has_gw) {
|
||||||
|
memcpy (&buffer[pos], &nexthop->gw, family_size);
|
||||||
|
pos += family_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* El contador de next-hops */
|
||||||
|
buffer[13]++;
|
||||||
|
|
||||||
|
g = g->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
send (manager_client->fd, buffer, pos, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _manager_send_route_del (ManagerClientInfo *manager_client, Route *route) {
|
||||||
|
unsigned char buffer[80];
|
||||||
|
int family_size = 0;
|
||||||
|
|
||||||
|
buffer[0] = NET_INADOR_TYPE_EVENT;
|
||||||
|
buffer[1] = NET_INADOR_EVENT_ROUTE_REMOVED;
|
||||||
|
|
||||||
|
/* Familia y máscara */
|
||||||
|
if (route->family == AF_INET) {
|
||||||
|
family_size = sizeof (struct in_addr);
|
||||||
|
} else if (route->family == AF_INET6) {
|
||||||
|
family_size = sizeof (struct in6_addr);
|
||||||
|
}
|
||||||
|
buffer[2] = route->family;
|
||||||
|
buffer[3] = route->type;
|
||||||
|
memcpy (&buffer[4], &route->table, 4);
|
||||||
|
buffer[8] = route->prefix;
|
||||||
|
memcpy (&buffer[9], &route->priority, 4);
|
||||||
|
|
||||||
|
/* Copiar la Ruta de destino */
|
||||||
|
memcpy (&buffer[13], &route->dest, family_size);
|
||||||
|
|
||||||
|
send (manager_client->fd, buffer, 13 + family_size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _manager_send_list_routes (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) {
|
||||||
|
int family;
|
||||||
|
GList *g;
|
||||||
|
Route *route;
|
||||||
|
uint32_t table;
|
||||||
|
|
||||||
|
if (buffer_len < 7) {
|
||||||
|
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_LIST_ROUTES);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
family = buffer[6];
|
||||||
|
|
||||||
|
if (family != AF_UNSPEC && family != AF_INET && family != AF_INET6) {
|
||||||
|
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_LIST_ROUTES);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&table, &buffer[2], 4);
|
||||||
|
|
||||||
|
if (family == AF_UNSPEC || family == AF_INET) {
|
||||||
|
for (g = manager_client->manager->handle->route_v4_tables; g != NULL; g = g->next) {
|
||||||
|
route = (Route *) g->data;
|
||||||
|
|
||||||
|
if (table != 0 && route->table != table) continue;
|
||||||
|
|
||||||
|
_manager_send_route (manager_client, route, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (family == AF_UNSPEC || family == AF_INET6) {
|
||||||
|
for (g = manager_client->manager->handle->route_v6_tables; g != NULL; g = g->next) {
|
||||||
|
route = (Route *) g->data;
|
||||||
|
|
||||||
|
if (table != 0 && route->table != table) continue;
|
||||||
|
|
||||||
|
_manager_send_route (manager_client, route, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_manager_send_end_command (manager_client, NET_INADOR_COMMAND_LIST_ROUTES);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition, gpointer data) {
|
static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||||
ManagerClientInfo *manager_client = (ManagerClientInfo *) data;
|
ManagerClientInfo *manager_client = (ManagerClientInfo *) data;
|
||||||
NetworkInadorManager *manager = manager_client->manager;
|
NetworkInadorManager *manager = manager_client->manager;
|
||||||
|
@ -1102,6 +1256,9 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition
|
||||||
case NET_INADOR_COMMAND_GET_DHCP_STATUS:
|
case NET_INADOR_COMMAND_GET_DHCP_STATUS:
|
||||||
_manager_execute_dhcp_get_status (manager_client, buffer, bytes);
|
_manager_execute_dhcp_get_status (manager_client, buffer, bytes);
|
||||||
break;
|
break;
|
||||||
|
case NET_INADOR_COMMAND_LIST_ROUTES:
|
||||||
|
_manager_send_list_routes (manager_client, buffer, bytes);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
_manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command);
|
_manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command);
|
||||||
}
|
}
|
||||||
|
@ -1246,6 +1403,48 @@ void manager_send_event_dhcp_change (NetworkInadorHandle *handle, InterfaceDHCPC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void manager_send_event_route_add (NetworkInadorHandle *handle, Route *route) {
|
||||||
|
char buffer_ip[1024];
|
||||||
|
inet_ntop (route->family, &route->dest, buffer_ip, sizeof (buffer_ip));
|
||||||
|
printf ("___ MANAGER ___ Informando ruta agregada: %s/%i [Tabla %i]\n", buffer_ip, route->prefix, route->table);
|
||||||
|
GList *g;
|
||||||
|
ManagerClientInfo *manager_client;
|
||||||
|
|
||||||
|
if (handle->manager == NULL) return;
|
||||||
|
|
||||||
|
for (g = handle->manager->connected_client_list; g != NULL; g = g->next) {
|
||||||
|
manager_client = (ManagerClientInfo *) g->data;
|
||||||
|
|
||||||
|
if (manager_client->wanted_events & NET_INADOR_EVENT_MASK_ROUTES) {
|
||||||
|
printf ("___ MANAGER ___ Informando a la conexión (%i)\n", manager_client->fd);
|
||||||
|
_manager_send_route (manager_client, route, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void manager_send_event_route_del (NetworkInadorHandle *handle, Route *route) {
|
||||||
|
char buffer_ip[1024];
|
||||||
|
inet_ntop (route->family, &route->dest, buffer_ip, sizeof (buffer_ip));
|
||||||
|
printf ("___ MANAGER ___ Informando ruta eliminada: %s/%i [Tabla %i]\n", buffer_ip, route->prefix, route->table);
|
||||||
|
GList *g;
|
||||||
|
ManagerClientInfo *manager_client;
|
||||||
|
|
||||||
|
if (handle->manager == NULL) return;
|
||||||
|
|
||||||
|
for (g = handle->manager->connected_client_list; g != NULL; g = g->next) {
|
||||||
|
manager_client = (ManagerClientInfo *) g->data;
|
||||||
|
|
||||||
|
if (manager_client->wanted_events & NET_INADOR_EVENT_MASK_ROUTES) {
|
||||||
|
printf ("___ MANAGER ___ Informando a la conexión (%i)\n", manager_client->fd);
|
||||||
|
_manager_send_route_del (manager_client, route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void manager_send_event_route_update (NetworkInadorHandle *handle, Route *route) {
|
||||||
|
manager_send_event_route_add (handle, route);
|
||||||
|
}
|
||||||
|
|
||||||
int manager_init (NetworkInadorHandle *handle) {
|
int manager_init (NetworkInadorHandle *handle) {
|
||||||
NetworkInadorManager *manager;
|
NetworkInadorManager *manager;
|
||||||
struct sockaddr_un socket_name;
|
struct sockaddr_un socket_name;
|
||||||
|
|
|
@ -34,6 +34,9 @@ void manager_send_event_interface_update (NetworkInadorHandle *handle, Interface
|
||||||
void manager_send_event_ip_add (NetworkInadorHandle *handle, IPAddr *ip_addr);
|
void manager_send_event_ip_add (NetworkInadorHandle *handle, IPAddr *ip_addr);
|
||||||
void manager_send_event_ip_del (NetworkInadorHandle *handle, IPAddr *ip_addr);
|
void manager_send_event_ip_del (NetworkInadorHandle *handle, IPAddr *ip_addr);
|
||||||
void manager_send_event_dhcp_change (NetworkInadorHandle *handle, InterfaceDHCPClientInfo *dhcpc);
|
void manager_send_event_dhcp_change (NetworkInadorHandle *handle, InterfaceDHCPClientInfo *dhcpc);
|
||||||
|
void manager_send_event_route_add (NetworkInadorHandle *handle, Route *route);
|
||||||
|
void manager_send_event_route_del (NetworkInadorHandle *handle, Route *route);
|
||||||
|
void manager_send_event_route_update (NetworkInadorHandle *handle, Route *route);
|
||||||
|
|
||||||
#endif /* __MANAGER_H__ */
|
#endif /* __MANAGER_H__ */
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "interfaces.h"
|
#include "interfaces.h"
|
||||||
#include "ip-address.h"
|
#include "ip-address.h"
|
||||||
|
#include "routes.h"
|
||||||
|
|
||||||
static int _netlink_events_route_dispatcher (struct nl_msg *msg, void *arg) {
|
static int _netlink_events_route_dispatcher (struct nl_msg *msg, void *arg) {
|
||||||
struct nlmsghdr *reply;
|
struct nlmsghdr *reply;
|
||||||
|
@ -51,6 +52,12 @@ static int _netlink_events_route_dispatcher (struct nl_msg *msg, void *arg) {
|
||||||
case RTM_DELADDR:
|
case RTM_DELADDR:
|
||||||
return ip_address_receive_message_deladdr (msg, arg);
|
return ip_address_receive_message_deladdr (msg, arg);
|
||||||
break;
|
break;
|
||||||
|
case RTM_NEWROUTE:
|
||||||
|
return routes_receive_message_newroute (msg, arg);
|
||||||
|
break;
|
||||||
|
case RTM_DELROUTE:
|
||||||
|
return routes_receive_message_delroute (msg, arg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NL_SKIP;
|
return NL_SKIP;
|
||||||
|
@ -104,7 +111,7 @@ void netlink_events_clear_pair (NetlinkEventPair *pair) {
|
||||||
void netlink_events_setup (NetworkInadorHandle *handle) {
|
void netlink_events_setup (NetworkInadorHandle *handle) {
|
||||||
netlink_events_create_pair (&handle->route_events, NETLINK_ROUTE);
|
netlink_events_create_pair (&handle->route_events, NETLINK_ROUTE);
|
||||||
|
|
||||||
nl_socket_add_memberships (handle->route_events.nl_sock, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_IFINFO, 0);
|
nl_socket_add_memberships (handle->route_events.nl_sock, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_IFINFO, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, 0);
|
||||||
nl_socket_modify_cb (handle->route_events.nl_sock, NL_CB_VALID, NL_CB_CUSTOM, _netlink_events_route_dispatcher, handle);
|
nl_socket_modify_cb (handle->route_events.nl_sock, NL_CB_VALID, NL_CB_CUSTOM, _netlink_events_route_dispatcher, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ enum {
|
||||||
#define NET_INADOR_EVENT_MASK_INTERFACES 0x01
|
#define NET_INADOR_EVENT_MASK_INTERFACES 0x01
|
||||||
#define NET_INADOR_EVENT_MASK_IP 0x02
|
#define NET_INADOR_EVENT_MASK_IP 0x02
|
||||||
#define NET_INADOR_EVENT_MASK_DHCP_STATUS 0x04
|
#define NET_INADOR_EVENT_MASK_DHCP_STATUS 0x04
|
||||||
|
#define NET_INADOR_EVENT_MASK_ROUTES 0x08
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NET_INADOR_COMMAND_LIST_IFACES = 1,
|
NET_INADOR_COMMAND_LIST_IFACES = 1,
|
||||||
|
@ -39,6 +40,8 @@ enum {
|
||||||
NET_INADOR_COMMAND_STOP_DHCP,
|
NET_INADOR_COMMAND_STOP_DHCP,
|
||||||
NET_INADOR_COMMAND_GET_DHCP_STATUS,
|
NET_INADOR_COMMAND_GET_DHCP_STATUS,
|
||||||
|
|
||||||
|
NET_INADOR_COMMAND_LIST_ROUTES = 64,
|
||||||
|
|
||||||
NET_INADOR_COMMAND_SET_EVENT_MASK = 192,
|
NET_INADOR_COMMAND_SET_EVENT_MASK = 192,
|
||||||
|
|
||||||
/* Los siguientes comandos son para uso interno */
|
/* Los siguientes comandos son para uso interno */
|
||||||
|
@ -63,7 +66,10 @@ enum {
|
||||||
NET_INADOR_EVENT_IFACE_REMOVED,
|
NET_INADOR_EVENT_IFACE_REMOVED,
|
||||||
NET_INADOR_EVENT_IPADDR_REMOVED,
|
NET_INADOR_EVENT_IPADDR_REMOVED,
|
||||||
|
|
||||||
NET_INADOR_EVENT_DHCP_STATUS = 6
|
NET_INADOR_EVENT_DHCP_STATUS = 6,
|
||||||
|
|
||||||
|
NET_INADOR_EVENT_ROUTE_ADDED = 10,
|
||||||
|
NET_INADOR_EVENT_ROUTE_REMOVED,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -72,7 +78,9 @@ enum {
|
||||||
NET_INADOR_RESPONSE_IFACE = 2,
|
NET_INADOR_RESPONSE_IFACE = 2,
|
||||||
NET_INADOR_RESPONSE_IPADDR,
|
NET_INADOR_RESPONSE_IPADDR,
|
||||||
|
|
||||||
NET_INADOR_RESPONSE_DHCP_STATUS = 6
|
NET_INADOR_RESPONSE_DHCP_STATUS = 6,
|
||||||
|
|
||||||
|
NET_INADOR_RESPONSE_ROUTE = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -0,0 +1,382 @@
|
||||||
|
/*
|
||||||
|
* routes.c
|
||||||
|
* This file is part of Network-inador
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 - Félix Arreola Rodríguez
|
||||||
|
*
|
||||||
|
* Network-inador is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Network-inador 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Network-inador; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
#include <netlink/socket.h>
|
||||||
|
#include <netlink/msg.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "routes.h"
|
||||||
|
#include "manager.h"
|
||||||
|
|
||||||
|
Route *_route_search_route (GList *list_routes, sa_family_t family, uint8_t type, uint32_t table, void *dest, uint32_t prefix, uint32_t priority) {
|
||||||
|
GList *g;
|
||||||
|
Route *route;
|
||||||
|
int family_size = 0;
|
||||||
|
|
||||||
|
if (family == AF_INET) {
|
||||||
|
family_size = sizeof (struct in_addr);
|
||||||
|
} else if (family == AF_INET6) {
|
||||||
|
family_size = sizeof (struct in6_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (g = list_routes; g != NULL; g = g->next) {
|
||||||
|
route = (Route *) g->data;
|
||||||
|
|
||||||
|
if (route->family != family) continue;
|
||||||
|
if (route->type != type) continue;
|
||||||
|
if (route->table != table) continue;
|
||||||
|
if (route->priority != priority) continue;
|
||||||
|
|
||||||
|
if (memcmp (&route->dest, dest, family_size) == 0 && route->prefix == prefix) {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int routes_receive_message_newroute (struct nl_msg *msg, void *arg) {
|
||||||
|
NetworkInadorHandle *handle = (NetworkInadorHandle *) arg;
|
||||||
|
struct nlmsghdr *reply;
|
||||||
|
Route *route = NULL;
|
||||||
|
uint32_t table, prefix;
|
||||||
|
int remaining, remaining2;
|
||||||
|
int family, family_size = 0;
|
||||||
|
struct rtmsg *rtm_hdr;
|
||||||
|
struct nlattr *attr, *nest_attr_gw;
|
||||||
|
RouteNH *next_hop;
|
||||||
|
struct rtnexthop *nhptr;
|
||||||
|
int rtnhp_len;
|
||||||
|
int multipath_len;
|
||||||
|
unsigned char *p;
|
||||||
|
uint8_t route_type;
|
||||||
|
struct_addr dest;
|
||||||
|
uint32_t priority = 0;
|
||||||
|
int was_new = 0;
|
||||||
|
GList *route_list = NULL;
|
||||||
|
|
||||||
|
reply = nlmsg_hdr (msg);
|
||||||
|
|
||||||
|
if (reply->nlmsg_type != RTM_NEWROUTE) return NL_SKIP;
|
||||||
|
|
||||||
|
/* Recuperar la tabla */
|
||||||
|
rtm_hdr = nlmsg_data (reply);
|
||||||
|
table = rtm_hdr->rtm_table;
|
||||||
|
|
||||||
|
/* Recuperar la familia */
|
||||||
|
family = rtm_hdr->rtm_family;
|
||||||
|
if (family == AF_INET) {
|
||||||
|
family_size = sizeof (struct in_addr);
|
||||||
|
route_list = handle->route_v4_tables;
|
||||||
|
} else if (family == AF_INET6) {
|
||||||
|
family_size = sizeof (struct in6_addr);
|
||||||
|
route_list = handle->route_v6_tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recuperar el tipo de ruta */
|
||||||
|
route_type = rtm_hdr->rtm_type;
|
||||||
|
|
||||||
|
/* Recuperar el prefijo */
|
||||||
|
prefix = rtm_hdr->rtm_dst_len;
|
||||||
|
|
||||||
|
/* Recuperar solo el destino */
|
||||||
|
memset (&dest, 0, sizeof (dest));
|
||||||
|
nlmsg_for_each_attr(attr, reply, sizeof (struct rtmsg), remaining) {
|
||||||
|
switch (nla_type (attr)) {
|
||||||
|
case RTA_DST:
|
||||||
|
if (nla_len (attr) != family_size) {
|
||||||
|
/* Tamaño incorrecto para la IP */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memcpy (&dest, nla_data (attr), family_size);
|
||||||
|
break;
|
||||||
|
case RTA_PRIORITY:
|
||||||
|
if (nla_len (attr) != 4) {
|
||||||
|
/* Tamaño incorrecto para la prioridad */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
priority = nla_get_u32 (attr);
|
||||||
|
break;
|
||||||
|
case RTA_TABLE:
|
||||||
|
if (nla_len (attr) != 4) {
|
||||||
|
/* Tamaño incorrecto para el id de la tabla */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
table = nla_get_u32 (attr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* TODO: Revisar si la ruta que procesamos ya existe */
|
||||||
|
route = _route_search_route (route_list, family, route_type, table, &dest, prefix, priority);
|
||||||
|
|
||||||
|
if (route == NULL) {
|
||||||
|
/* Nueva ruta */
|
||||||
|
route = (Route *) malloc (sizeof (Route));
|
||||||
|
memset (route, 0, sizeof (Route));
|
||||||
|
|
||||||
|
route->family = family;
|
||||||
|
route->type = route_type;
|
||||||
|
route->table = table;
|
||||||
|
route->prefix = prefix;
|
||||||
|
|
||||||
|
route->priority = priority;
|
||||||
|
memcpy (&route->dest, &dest, family_size);
|
||||||
|
|
||||||
|
if (family == AF_INET) {
|
||||||
|
handle->route_v4_tables = g_list_append (handle->route_v4_tables, route);
|
||||||
|
} else if (family == AF_INET6) {
|
||||||
|
handle->route_v6_tables = g_list_append (handle->route_v6_tables, route);
|
||||||
|
}
|
||||||
|
was_new = 1;
|
||||||
|
} else {
|
||||||
|
/* Liberar los next-hops, puesto que volverán a ser creados */
|
||||||
|
g_list_free_full (route->nexthops, free);
|
||||||
|
route->nexthops = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
route->protocol = rtm_hdr->rtm_protocol;
|
||||||
|
route->tos = rtm_hdr->rtm_tos;
|
||||||
|
route->scope = rtm_hdr->rtm_scope;
|
||||||
|
|
||||||
|
/* Pre-reservar el primer siguiente brinco y ligar */
|
||||||
|
next_hop = (RouteNH *) malloc (sizeof (RouteNH));
|
||||||
|
memset (next_hop, 0, sizeof (RouteNH));
|
||||||
|
|
||||||
|
nlmsg_for_each_attr(attr, reply, sizeof (struct rtmsg), remaining) {
|
||||||
|
switch (nla_type (attr)) {
|
||||||
|
case RTA_PREFSRC:
|
||||||
|
if (nla_len (attr) != family_size) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memcpy (&route->prefsrc, nla_data (attr), family_size);
|
||||||
|
break;
|
||||||
|
case RTA_GATEWAY:
|
||||||
|
if (nla_len (attr) != family_size) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memcpy (&next_hop->gw, nla_data (attr), family_size);
|
||||||
|
break;
|
||||||
|
case RTA_OIF:
|
||||||
|
if (nla_len (attr) != 4) {
|
||||||
|
/* Tamaño incorrecto para el índice de la interfaz */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
next_hop->out_index = nla_get_u32 (attr);
|
||||||
|
break;
|
||||||
|
/* TODO: Revisar si RTA_PREF, RTA_CACHEINFO es útil */
|
||||||
|
case RTA_MULTIPATH:
|
||||||
|
nhptr = (struct rtnexthop*) nla_data (attr);
|
||||||
|
multipath_len = nla_len (attr);
|
||||||
|
|
||||||
|
while (multipath_len > 0) {
|
||||||
|
next_hop->nh_flags = nhptr->rtnh_flags;
|
||||||
|
next_hop->nh_weight = nhptr->rtnh_hops;
|
||||||
|
next_hop->out_index = nhptr->rtnh_ifindex;
|
||||||
|
|
||||||
|
/* Revisar en los atributos si tiene gw */
|
||||||
|
p = ((unsigned char *) nhptr) + sizeof (struct rtnexthop);
|
||||||
|
nest_attr_gw = nla_find ((const struct nlattr *) p, nhptr->rtnh_len - sizeof (struct rtnexthop), RTA_GATEWAY);
|
||||||
|
|
||||||
|
if (nest_attr_gw != NULL && nla_len (nest_attr_gw) == family_size) {
|
||||||
|
memcpy (&next_hop->gw, nla_data (nest_attr_gw), family_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
multipath_len -= nhptr->rtnh_len;
|
||||||
|
nhptr = (struct rtnexthop *) (((unsigned char *) nhptr) + nhptr->rtnh_len);
|
||||||
|
|
||||||
|
/* Reservar el siguiente next-hop */
|
||||||
|
if (multipath_len > 0) {
|
||||||
|
route->nexthops = g_list_append (route->nexthops, next_hop);
|
||||||
|
|
||||||
|
next_hop = (RouteNH *) malloc (sizeof (RouteNH));
|
||||||
|
memset (next_hop, 0, sizeof (RouteNH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
route->nexthops = g_list_append (route->nexthops, next_hop);
|
||||||
|
|
||||||
|
if (was_new) {
|
||||||
|
/* Enviar aquí evento de ruta agregada */
|
||||||
|
manager_send_event_route_add (handle, route);
|
||||||
|
} else {
|
||||||
|
/* Enviar actualización */
|
||||||
|
manager_send_event_route_update (handle, route);
|
||||||
|
}
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int routes_receive_message_delroute (struct nl_msg *msg, void *arg) {
|
||||||
|
NetworkInadorHandle *handle = (NetworkInadorHandle *) arg;
|
||||||
|
struct nlmsghdr *reply;
|
||||||
|
Route *route = NULL;
|
||||||
|
uint32_t table, prefix;
|
||||||
|
int remaining;
|
||||||
|
int family, family_size = 0;
|
||||||
|
struct rtmsg *rtm_hdr;
|
||||||
|
struct nlattr *attr;
|
||||||
|
uint8_t route_type;
|
||||||
|
struct_addr dest;
|
||||||
|
uint32_t priority = 0;
|
||||||
|
GList *route_list = NULL;
|
||||||
|
|
||||||
|
reply = nlmsg_hdr (msg);
|
||||||
|
if (reply->nlmsg_type != RTM_DELROUTE) return NL_SKIP;
|
||||||
|
|
||||||
|
/* Recuperar la tabla */
|
||||||
|
rtm_hdr = nlmsg_data (reply);
|
||||||
|
table = rtm_hdr->rtm_table;
|
||||||
|
|
||||||
|
/* Recuperar la familia */
|
||||||
|
family = rtm_hdr->rtm_family;
|
||||||
|
if (family == AF_INET) {
|
||||||
|
family_size = sizeof (struct in_addr);
|
||||||
|
route_list = handle->route_v4_tables;
|
||||||
|
} else if (family == AF_INET6) {
|
||||||
|
family_size = sizeof (struct in6_addr);
|
||||||
|
route_list = handle->route_v6_tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recuperar el tipo de ruta */
|
||||||
|
route_type = rtm_hdr->rtm_type;
|
||||||
|
|
||||||
|
/* Recuperar el prefijo */
|
||||||
|
prefix = rtm_hdr->rtm_dst_len;
|
||||||
|
|
||||||
|
/* Recuperar solo el destino */
|
||||||
|
memset (&dest, 0, sizeof (dest));
|
||||||
|
nlmsg_for_each_attr(attr, reply, sizeof (struct rtmsg), remaining) {
|
||||||
|
switch (nla_type (attr)) {
|
||||||
|
case RTA_DST:
|
||||||
|
if (nla_len (attr) != family_size) {
|
||||||
|
/* Tamaño incorrecto para la IP */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memcpy (&dest, nla_data (attr), family_size);
|
||||||
|
break;
|
||||||
|
case RTA_PRIORITY:
|
||||||
|
if (nla_len (attr) != 4) {
|
||||||
|
/* Tamaño incorrecto para la prioridad */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
priority = nla_get_u32 (attr);
|
||||||
|
break;
|
||||||
|
case RTA_TABLE:
|
||||||
|
if (nla_len (attr) != 4) {
|
||||||
|
/* Tamaño incorrecto para el id de la tabla */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
table = nla_get_u32 (attr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
route = _route_search_route (route_list, family, route_type, table, &dest, prefix, priority);
|
||||||
|
|
||||||
|
if (route == NULL) {
|
||||||
|
/* ¿Notificación de eliminar una ruta que no existe? Super raro */
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (family == AF_INET) {
|
||||||
|
/* Eliminar de la lista ligada */
|
||||||
|
handle->route_v4_tables = g_list_remove (handle->route_v4_tables, route);
|
||||||
|
} else if (family == AF_INET6) {
|
||||||
|
handle->route_v6_tables = g_list_remove (handle->route_v6_tables, route);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notificar del evento */
|
||||||
|
manager_send_event_route_del (handle, route);
|
||||||
|
|
||||||
|
/* Eliminar todos los next-hops primero */
|
||||||
|
g_list_free_full (route->nexthops, free);
|
||||||
|
|
||||||
|
free (route);
|
||||||
|
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
void routes_init (NetworkInadorHandle *handle) {
|
||||||
|
/* Si es la primera vez que nos llaman, descargar una primera lista de interfaces */
|
||||||
|
struct nl_msg * msg;
|
||||||
|
struct rtmsg rtm_hdr = {
|
||||||
|
.rtm_family = AF_UNSPEC,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
msg = nlmsg_alloc_simple (RTM_GETROUTE, NLM_F_REQUEST | NLM_F_DUMP);
|
||||||
|
if (msg == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret = nlmsg_append (msg, &rtm_hdr, sizeof (rtm_hdr), NLMSG_ALIGNTO);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
nlmsg_free (msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_complete_msg (handle->nl_sock_route, msg);
|
||||||
|
|
||||||
|
ret = nl_send (handle->nl_sock_route, msg);
|
||||||
|
|
||||||
|
nlmsg_free (msg);
|
||||||
|
|
||||||
|
nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, routes_receive_message_newroute, handle);
|
||||||
|
|
||||||
|
nl_recvmsgs_default (handle->nl_sock_route);
|
||||||
|
}
|
||||||
|
|
||||||
|
void routes_clean_up (NetworkInadorHandle *handle) {
|
||||||
|
GList *g;
|
||||||
|
Route *route;
|
||||||
|
|
||||||
|
for (g = handle->route_v4_tables; g != NULL; g = g->next) {
|
||||||
|
route = (Route *) g->data;
|
||||||
|
|
||||||
|
g_list_free_full (route->nexthops, free);
|
||||||
|
route->nexthops = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (handle->route_v4_tables, free);
|
||||||
|
handle->route_v4_tables = NULL;
|
||||||
|
|
||||||
|
for (g = handle->route_v6_tables; g != NULL; g = g->next) {
|
||||||
|
route = (Route *) g->data;
|
||||||
|
|
||||||
|
g_list_free_full (route->nexthops, free);
|
||||||
|
route->nexthops = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (handle->route_v6_tables, free);
|
||||||
|
handle->route_v6_tables = NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* routes.h
|
||||||
|
* This file is part of Network-inador
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 - Félix Arreola Rodríguez
|
||||||
|
*
|
||||||
|
* Network-inador is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Network-inador 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Network-inador; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ROUTES_H__
|
||||||
|
#define __ROUTES_H__
|
||||||
|
|
||||||
|
#include <netlink/socket.h>
|
||||||
|
#include <netlink/msg.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
void routes_init (NetworkInadorHandle *handle);
|
||||||
|
int routes_receive_message_newroute (struct nl_msg *msg, void *arg);
|
||||||
|
int routes_receive_message_delroute (struct nl_msg *msg, void *arg);
|
||||||
|
|
||||||
|
void routes_clean_up (NetworkInadorHandle *handle);
|
||||||
|
|
||||||
|
#endif /* __ROUTES_H__ */
|
||||||
|
|
Loading…
Reference in New Issue