diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c new file mode 100644 index 0000000000..6b61d87658 --- /dev/null +++ b/src/rdisc/nm-lndp-rdisc.c @@ -0,0 +1,631 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-lndp-rdisc.c - Router discovery implementation using libndp + * + * This program 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, or (at your option) + * any later version. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#include +#include +/* stdarg.h included because of a bug in ndp.h */ +#include +#include + +#include "nm-lndp-rdisc.h" + +#include "nm-logging.h" + +#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__) +#define warning(...) nm_log_warn (LOGD_IP6, __VA_ARGS__) +#define error(...) nm_log_err (LOGD_IP6, __VA_ARGS__) + +typedef struct { + struct ndp *ndp; + + guint send_rs_id; + GIOChannel *event_channel; + guint event_id; + guint timeout_id; +} NMLNDPRDiscPrivate; + +#define NM_LNDP_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LNDP_RDISC, NMLNDPRDiscPrivate)) + +G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC) + +/******************************************************************/ + +NMRDisc * +nm_lndp_rdisc_new (int ifindex, const char *ifname) +{ + NMRDisc *rdisc = g_object_new (NM_TYPE_LNDP_RDISC, NULL); + + g_assert (rdisc); + + rdisc->ifindex = ifindex; + rdisc->ifname = g_strdup (ifname); + + return rdisc; +} + +static gboolean +add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new) +{ + int i; + + for (i = 0; i < rdisc->gateways->len; i++) { + NMRDiscGateway *item = &g_array_index (rdisc->gateways, NMRDiscGateway, i); + + if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { + if (item->preference != new->preference) { + g_array_remove_index (rdisc->gateways, i--); + continue; + } + memcpy (item, new, sizeof (*new)); + return FALSE; + } + + /* Put before less preferable gateways. */ + if (item->preference < new->preference) + break; + } + + g_array_insert_val (rdisc->gateways, i, *new); + return TRUE; +} + +static gboolean +add_address (NMRDisc *rdisc, const NMRDiscAddress *new) +{ + int i; + + for (i = 0; i < rdisc->addresses->len; i++) { + NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); + + if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { + memcpy (item, new, sizeof (*new)); + return FALSE; + } + } + + g_array_insert_val (rdisc->addresses, i, *new); + return TRUE; +} + +static gboolean +add_route (NMRDisc *rdisc, const NMRDiscRoute *new) +{ + int i; + + for (i = 0; i < rdisc->routes->len; i++) { + NMRDiscRoute *item = &g_array_index (rdisc->routes, NMRDiscRoute, i); + + if (IN6_ARE_ADDR_EQUAL (&item->network, &new->network) && item->plen == new->plen) { + if (item->preference != new->preference) { + g_array_remove_index (rdisc->routes, i--); + continue; + } + memcpy (item, new, sizeof (*new)); + return FALSE; + } + + /* Put before less preferable routes. */ + if (item->preference < new->preference) + break; + } + + g_array_insert_val (rdisc->routes, i, *new); + return TRUE; +} + +static gboolean +add_server (NMRDisc *rdisc, const NMRDiscDNSServer *new) +{ + int i; + + for (i = 0; i < rdisc->dns_servers->len; i++) { + NMRDiscDNSServer *item = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i); + + if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) + return FALSE; + } + + g_array_insert_val (rdisc->dns_servers, i, *new); + + return TRUE; +} + +static gboolean +add_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new) +{ + int i; + + for (i = 0; i < rdisc->dns_domains->len; i++) { + NMRDiscDNSDomain *item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i); + + if (!g_strcmp0 (item->domain, new->domain)) + return FALSE; + } + + g_array_insert_val (rdisc->dns_domains, i, *new); + + return TRUE; +} + +#define RETRY 10 + +static gboolean +send_rs (NMRDisc *rdisc) +{ + NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); + struct ndp_msg *msg; + int error; + + error = ndp_msg_new (&msg, NDP_MSG_RS); + g_assert (!error); + ndp_msg_ifindex_set (msg, rdisc->ifindex); + + debug ("(%s): sending router solicitation: %d", rdisc->ifname, rdisc->ifindex); + + error = ndp_msg_send (priv->ndp, msg); + if (error) + error ("(%s): cannot send router solicitation: %d.", rdisc->ifname, error); + + ndp_msg_destroy (msg); + + debug ("(%s): scheduling router solicitation retry in %d seconds.", rdisc->ifname, RETRY); + priv->send_rs_id = g_timeout_add_seconds (RETRY, (GSourceFunc) send_rs, rdisc); + + return FALSE; +} + +static void +solicit (NMRDisc *rdisc) +{ + NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); + + if (!priv->send_rs_id) { + debug ("(%s): scheduling router solicitation.", rdisc->ifname); + priv->send_rs_id = g_idle_add ((GSourceFunc) send_rs, rdisc); + } +} + +static void +clean_gateways (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +{ + int i; + + for (i = 0; i < rdisc->gateways->len; i++) { + NMRDiscGateway *item = &g_array_index (rdisc->gateways, NMRDiscGateway, i); + guint32 expiry = item->timestamp + item->lifetime; + + if (item->lifetime == UINT_MAX) + continue; + + if (now >= expiry) { + g_array_remove_index (rdisc->gateways, i--); + *changed |= NM_RDISC_CONFIG_GATEWAYS; + } else if (*nextevent > expiry) + *nextevent = expiry; + } +} + +static void +clean_addresses (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +{ + int i; + + for (i = 0; i < rdisc->addresses->len; i++) { + NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); + guint32 expiry = item->timestamp + item->lifetime; + + if (item->lifetime == UINT_MAX) + continue; + + if (now >= expiry) { + g_array_remove_index (rdisc->addresses, i--); + *changed |= NM_RDISC_CONFIG_ADDRESSES; + } else if (*nextevent > expiry) + *nextevent = expiry; + } +} + +static void +clean_routes (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +{ + int i; + + for (i = 0; i < rdisc->routes->len; i++) { + NMRDiscRoute *item = &g_array_index (rdisc->routes, NMRDiscRoute, i); + guint32 expiry = item->timestamp + item->lifetime; + + if (item->lifetime == UINT_MAX) + continue; + + if (now >= expiry) { + g_array_remove_index (rdisc->routes, i--); + *changed |= NM_RDISC_CONFIG_ROUTES; + } else if (*nextevent > expiry) + *nextevent = expiry; + } +} + +static void +clean_servers (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +{ + int i; + + for (i = 0; i < rdisc->dns_servers->len; i++) { + NMRDiscDNSServer *item = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i); + guint32 expiry = item->timestamp + item->lifetime; + guint32 refresh = item->timestamp + item->lifetime / 2; + + if (item->lifetime == UINT_MAX) + continue; + + if (now >= expiry) { + g_array_remove_index (rdisc->dns_servers, i--); + *changed |= NM_RDISC_CONFIG_ROUTES; + } else if (now >= refresh) + solicit (rdisc); + else if (*nextevent > refresh) + *nextevent = refresh; + } +} + +static void +clean_domains (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +{ + int i; + + for (i = 0; i < rdisc->dns_domains->len; i++) { + NMRDiscDNSDomain *item = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i); + guint32 expiry = item->timestamp + item->lifetime; + guint32 refresh = item->timestamp + item->lifetime / 2; + + if (item->lifetime == UINT_MAX) + continue; + + if (now >= expiry) { + g_array_remove_index (rdisc->dns_domains, i--); + *changed |= NM_RDISC_CONFIG_ROUTES; + } else if (now >= refresh) + solicit (rdisc); + else if (*nextevent >=refresh) + *nextevent = refresh; + } +} + +static gboolean timeout_cb (gpointer user_data); + +static void +check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) +{ + NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); + /* Use a magic date in distant enough future as there's no guint32 max macro. */ + guint32 never = G_MAXINT32; + guint32 nextevent = never; + + if (priv->timeout_id) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + + clean_gateways (rdisc, now, &changed, &nextevent); + clean_addresses (rdisc, now, &changed, &nextevent); + clean_routes (rdisc, now, &changed, &nextevent); + clean_servers (rdisc, now, &changed, &nextevent); + clean_domains (rdisc, now, &changed, &nextevent); + + if (changed) + g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, changed); + + if (nextevent != never) { + debug ("Scheduling next now/lifetime check: %d seconds", (int) nextevent); + priv->timeout_id = g_timeout_add_seconds (nextevent, timeout_cb, rdisc); + } +} + +static guint32 +get_time (void) +{ + struct timespec tp; + + clock_gettime (CLOCK_MONOTONIC, &tp); + + return tp.tv_sec; +} + +static gboolean +timeout_cb (gpointer user_data) +{ + check_timestamps (user_data, get_time (), 0); + + return TRUE; +} + +static NMRDiscPreference +translate_preference (enum ndp_route_preference preference) +{ + switch (preference) { + case NDP_ROUTE_PREF_LOW: + return NM_RDISC_PREFERENCE_LOW; + case NDP_ROUTE_PREF_MEDIUM: + return NM_RDISC_PREFERENCE_MEDIUM; + case NDP_ROUTE_PREF_HIGH: + return NM_RDISC_PREFERENCE_HIGH; + default: + return NM_RDISC_PREFERENCE_INVALID; + } +} + +static void +fill_address_from_mac (struct in6_addr *address, const char *mac) +{ + unsigned char *identifier = address->s6_addr + 8; + + if (!mac) + return; + + /* Translate 48-bit MAC address to a 64-bit modified interface identifier + * and write it to the second half of the IPv6 address. + * + * See http://tools.ietf.org/html/rfc3513#page-21 + */ + memcpy (identifier, mac, 3); + identifier[0] ^= 0x02; + identifier[3] = 0xff; + identifier[4] = 0xfe; + memcpy (identifier + 5, mac + 3, 3); +} + +static int +receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) +{ + NMRDisc *rdisc = (NMRDisc *) user_data; + NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); + NMRDiscConfigMap changed = 0; + size_t lladdrlen; + const char *lladdr = g_bytes_get_data (rdisc->lladdr, &lladdrlen); + struct ndp_msgra *msgra = ndp_msgra (msg); + NMRDiscGateway gateway; + guint32 now = get_time (); + int offset; + + /* Router discovery is subject to the following RFC documents: + * + * http://tools.ietf.org/html/rfc4861 + * http://tools.ietf.org/html/rfc4862 + * + * The biggest difference from good old DHCP is that all configuration + * items have their own lifetimes and they are merged from various + * sources. Router discovery is *not* contract-based, so there is *no* + * single time when the configuration is finished and updates can + * come at any time. + */ + debug ("Recieved router advertisement: %d at %d", rdisc->ifindex, (int) now); + + if (priv->send_rs_id) { + g_source_remove (priv->send_rs_id); + priv->send_rs_id = 0; + } + + /* DHCP level: + * + * The problem with DHCP level is what to do if subsequent + * router advertisements carry different flags. Currently we just + * rewrite the flag with every inbound RA. + */ + { + NMRDiscDHCPLevel dhcp_level; + + if (ndp_msgra_flag_managed (msgra)) + dhcp_level = NM_RDISC_DHCP_LEVEL_MANAGED; + else if (ndp_msgra_flag_other (msgra)) + dhcp_level = NM_RDISC_DHCP_LEVEL_OTHERCONF; + else + dhcp_level = NM_RDISC_DHCP_LEVEL_NONE; + + if (dhcp_level != rdisc->dhcp_level) { + rdisc->dhcp_level = dhcp_level; + changed |= NM_RDISC_CONFIG_DHCP_LEVEL; + } + } + + /* Default gateway: + * + * Subsequent router advertisements can represent new default gateways + * on the network. We should present all of them in router preference + * order. + */ + memset (&gateway, 0, sizeof (gateway)); + gateway.address = *ndp_msg_addrto (msg); + gateway.timestamp = now; + gateway.lifetime = ndp_msgra_router_lifetime (msgra); + gateway.preference = translate_preference (ndp_msgra_route_preference (msgra)); + if (add_gateway (rdisc, &gateway)) + changed |= NM_RDISC_CONFIG_GATEWAYS; + + /* Addresses & Routes */ + ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_PREFIX) { + NMRDiscRoute route; + NMRDiscAddress address; + + /* Device route */ + memset (&route, 0, sizeof (route)); + route.network = *ndp_msg_opt_prefix (msg, offset); + route.plen = ndp_msg_opt_prefix_len (msg, offset); + route.timestamp = now; + if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) { + route.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset); + if (add_route (rdisc, &route)) + changed |= NM_RDISC_CONFIG_ROUTES; + } + + /* Address */ + if (ndp_msg_opt_prefix_flag_auto_addr_conf (msg, offset)) { + if (route.plen == 64 && lladdrlen == 6) { + memset (&address, 0, sizeof (address)); + address.address = route.network; + address.timestamp = now; + address.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset); + address.preferred_lft = ndp_msg_opt_prefix_preferred_time (msg, offset); + + fill_address_from_mac (&address.address, lladdr); + + if (add_address (rdisc, &address)) + changed |= NM_RDISC_CONFIG_ADDRESSES; + } + } + } + ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_ROUTE) { + NMRDiscRoute route; + + /* Routers through this particular gateway */ + memset (&route, 0, sizeof (route)); + route.gateway = gateway.address; + route.network = *ndp_msg_opt_route_prefix (msg, offset); + route.plen = ndp_msg_opt_route_prefix_len (msg, offset); + route.timestamp = now; + route.lifetime = ndp_msg_opt_route_lifetime (msg, offset); + route.preference = translate_preference (ndp_msg_opt_route_preference (msg, offset)); + if (add_route (rdisc, &route)) + changed |= NM_RDISC_CONFIG_ROUTES; + } + + /* DNS information */ + ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_RDNSS) { + static struct in6_addr *addr; + int addr_index; + + ndp_msg_opt_rdnss_for_each_addr (addr, addr_index, msg, offset) { + NMRDiscDNSServer dns_server; + + memset (&dns_server, 0, sizeof (dns_server)); + dns_server.address = *addr; + dns_server.timestamp = now; + dns_server.lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset); + /* Pad the lifetime somewhat to give a bit of slack in cases + * where one RA gets lost or something (which can happen on unreliable + * links like WiFi where certain types of frames are not retransmitted). + * Note that 0 has special meaning and is therefore not adjusted. + */ + if (dns_server.lifetime && dns_server.lifetime < 7200) + dns_server.lifetime = 7200; + if (add_server (rdisc, &dns_server)) + changed |= NM_RDISC_CONFIG_DNS_SERVERS; + } + } + ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_DNSSL) { + char *domain; + int domain_index; + + ndp_msg_opt_dnssl_for_each_domain (domain, domain_index, msg, offset) { + NMRDiscDNSDomain dns_domain; + + memset (&dns_domain, 0, sizeof (dns_domain)); + dns_domain.domain = g_strdup (domain); + dns_domain.timestamp = now; + dns_domain.lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset); + /* Pad the lifetime somewhat to give a bit of slack in cases + * where one RA gets lost or something (which can happen on unreliable + * links like WiFi where certain types of frames are not retransmitted). + * Note that 0 has special meaning and is therefore not adjusted. + */ + if (dns_domain.lifetime && dns_domain.lifetime < 7200) + dns_domain.lifetime = 7200; + if (add_domain (rdisc, &dns_domain)) + changed |= NM_RDISC_CONFIG_DNS_DOMAINS; + } + } + + check_timestamps (rdisc, now, changed); + + return 0; +} + +static void +process_events (NMRDisc *rdisc) +{ + NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); + + debug ("(%s): processing libndp events.", rdisc->ifname); + ndp_callall_eventfd_handler (priv->ndp); +} + +static gboolean +event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc) +{ + process_events (rdisc); + + return TRUE; +} + +static void +start (NMRDisc *rdisc) +{ + NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); + int fd = ndp_get_eventfd (priv->ndp); + + priv->event_channel = g_io_channel_unix_new (fd); + priv->event_id = g_io_add_watch (priv->event_channel, G_IO_IN, (GIOFunc) event_ready, rdisc); + + /* Flush any pending messages to avoid using obsolete information */ + process_events (rdisc); + + ndp_msgrcv_handler_register (priv->ndp, &receive_ra, NDP_MSG_RA, rdisc->ifindex, rdisc); + solicit (rdisc); +} + +/******************************************************************/ + +static void +nm_lndp_rdisc_init (NMLNDPRDisc *lndp_rdisc) +{ + NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (lndp_rdisc); + int error; + + error = ndp_open (&priv->ndp); + g_assert (!error); +} + +static void +nm_lndp_rdisc_finalize (GObject *object) +{ + NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (object); + + if (priv->send_rs_id) + g_source_remove (priv->send_rs_id); + if (priv->timeout_id) + g_source_remove (priv->timeout_id); + if (priv->event_channel) + g_io_channel_unref (priv->event_channel); + if (priv->event_id) + g_source_remove (priv->event_id); + + ndp_close (priv->ndp); +} + +static void +nm_lndp_rdisc_class_init (NMLNDPRDiscClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMRDiscClass *rdisc_class = NM_RDISC_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMLNDPRDiscPrivate)); + + object_class->finalize = nm_lndp_rdisc_finalize; + rdisc_class->start = start; +} diff --git a/src/rdisc/nm-lndp-rdisc.h b/src/rdisc/nm-lndp-rdisc.h new file mode 100644 index 0000000000..eb6a1df6d9 --- /dev/null +++ b/src/rdisc/nm-lndp-rdisc.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-lndp-rdisc.h - Implementation of router discovery using libndp + * + * This program 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, or (at your option) + * any later version. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#ifndef NM_LNDP_RDISC_H +#define NM_LNDP_RDISC_H + +#include "nm-rdisc.h" + +#define NM_TYPE_LNDP_RDISC (nm_lndp_rdisc_get_type ()) +#define NM_LNDP_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LNDP_RDISC, NMLNDPRDisc)) +#define NM_LNDP_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_LNDP_RDISC, NMLNDPRDiscClass)) +#define NM_IS_LNDP_RDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_LNDP_RDISC)) +#define NM_IS_LNDP_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_LNDP_RDISC)) +#define NM_LNDP_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_LNDP_RDISC, NMLNDPRDiscClass)) + +/******************************************************************/ + +typedef struct { + NMRDisc parent; +} NMLNDPRDisc; + +typedef struct { + NMRDiscClass parent; +} NMLNDPRDiscClass; + +/******************************************************************/ + +GType nm_lndp_rdisc_get_type (void); + +NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname); + +#endif /* NM_LNDP_RDISC_H */ diff --git a/src/rdisc/tests/Makefile.am b/src/rdisc/tests/Makefile.am index 8e3843b7ec..7308cfe973 100644 --- a/src/rdisc/tests/Makefile.am +++ b/src/rdisc/tests/Makefile.am @@ -5,7 +5,8 @@ AM_CPPFLAGS = \ -I${top_srcdir}/libnm-util \ -I${srcdir}/.. \ $(GLIB_CFLAGS) \ - $(LIBNL_CFLAGS) + $(LIBNL_CFLAGS) \ + $(LIBNDP_CFLAGS) AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) AM_LDFLAGS = $(GLIB_LIBS) $(CODE_COVERAGE_LDFLAGS) @@ -19,4 +20,6 @@ rdisc_SOURCES = \ rdisc.c \ ../nm-rdisc.c \ ../nm-fake-rdisc.c \ + ../nm-lndp-rdisc.c \ ../../logging/nm-logging.c +rdisc_LDADD = $(LIBNDP_LIBS) diff --git a/src/rdisc/tests/rdisc.c b/src/rdisc/tests/rdisc.c index 4d8a95b025..89da3154dc 100644 --- a/src/rdisc/tests/rdisc.c +++ b/src/rdisc/tests/rdisc.c @@ -1,7 +1,10 @@ +#include #include +#include #include "nm-rdisc.h" #include "nm-fake-rdisc.h" +#include "nm-lndp-rdisc.h" #include "nm-logging.h" int @@ -9,13 +12,30 @@ main (int argc, char **argv) { GMainLoop *loop; NMRDisc *rdisc; + NMRDisc *(*new) (int ifindex, const char *ifname) = nm_lndp_rdisc_new; + int ifindex = 1; + char ifname[IF_NAMESIZE]; + char mac[6] = { 0x02, 0xaa, 0xbb, 0xcc, 0xdd, 0xee }; + + if_indextoname (ifindex, ifname); g_type_init (); loop = g_main_loop_new (NULL, FALSE); nm_logging_setup ("debug", NULL, NULL); openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_DAEMON); - rdisc = nm_fake_rdisc_new (1); + argv++; + for (; *argv; argv++) { + if (!g_strcmp0 (*argv, "--fake")) + new = nm_fake_rdisc_new; + else { + strncpy (ifname, *argv, IF_NAMESIZE); + ifindex = if_nametoindex (ifname); + } + } + + rdisc = new (ifindex, ifname); + nm_rdisc_set_lladdr (rdisc, mac, 6); nm_rdisc_start (rdisc); g_main_loop_run (loop);