diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index bc621dd68a..8de188c513 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -381,6 +381,136 @@ nm_ip4_config_merge (NMIP4Config *dst, NMIP4Config *src) nm_ip4_config_add_wins (dst, nm_ip4_config_get_wins (src, i)); } +/** + * nm_ip4_config_subtract() + * @dst: config from which to remove everything in @src + * @src: config to remove from @dst + * + * Removes everything in @src from @dst. + * + */ +void +nm_ip4_config_subtract (NMIP4Config *dst, NMIP4Config *src) +{ + guint32 i, j; + + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); + + /* addresses */ + for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++) { + const NMPlatformIP4Address *src_addr = nm_ip4_config_get_address (src, i); + + for (j = 0; j < nm_ip4_config_get_num_addresses (dst); j++) { + const NMPlatformIP4Address *dst_addr = nm_ip4_config_get_address (dst, j); + + if (src_addr->address == dst_addr->address && + src_addr->plen == dst_addr->plen) { + nm_ip4_config_del_address (dst, j); + break; + } + } + } + + /* ptp address */ + if (nm_ip4_config_get_ptp_address (src) == nm_ip4_config_get_ptp_address (dst)) + nm_ip4_config_set_ptp_address (dst, 0); + + /* nameservers */ + for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) { + guint32 src_ns = nm_ip4_config_get_nameserver (src, i); + + for (j = 0; j < nm_ip4_config_get_num_nameservers (dst); j++) { + guint32 dst_ns = nm_ip4_config_get_nameserver (dst, j); + + if (dst_ns == src_ns) { + nm_ip4_config_del_nameserver (dst, j); + break; + } + } + } + + /* default gateway */ + if (nm_ip4_config_get_gateway (src) == nm_ip4_config_get_gateway (dst)) + nm_ip4_config_set_gateway (dst, 0); + + /* routes */ + for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) { + NMIP4Route *src_route = nm_ip4_config_get_route (src, i); + + for (j = 0; j < nm_ip4_config_get_num_routes (dst); j++) { + NMIP4Route *dst_route = nm_ip4_config_get_route (dst, j); + + if (nm_ip4_route_compare (src_route, dst_route)) { + nm_ip4_config_del_route (dst, j); + break; + } + } + } + + /* domains */ + for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) { + const char *src_domain = nm_ip4_config_get_domain (src, i); + + for (j = 0; j < nm_ip4_config_get_num_domains (dst); j++) { + const char *dst_domain = nm_ip4_config_get_domain (dst, j); + + if (g_strcmp0 (src_domain, dst_domain) == 0) { + nm_ip4_config_del_domain (dst, j); + break; + } + } + } + + /* dns searches */ + for (i = 0; i < nm_ip4_config_get_num_searches (src); i++) { + const char *src_search = nm_ip4_config_get_search (src, i); + + for (j = 0; j < nm_ip4_config_get_num_searches (dst); j++) { + const char *dst_search = nm_ip4_config_get_search (dst, j); + + if (g_strcmp0 (src_search, dst_search) == 0) { + nm_ip4_config_del_search (dst, j); + break; + } + } + } + + if (nm_ip4_config_get_mss (src) == nm_ip4_config_get_mss (dst)) + nm_ip4_config_set_mss (dst, 0); + + /* NIS */ + for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++) { + guint32 src_nis = nm_ip4_config_get_nis_server (src, i); + + for (j = 0; j < nm_ip4_config_get_num_nis_servers (dst); j++) { + guint32 dst_nis = nm_ip4_config_get_nis_server (dst, j); + + if (dst_nis == src_nis) { + nm_ip4_config_del_nis_server (dst, j); + break; + } + } + } + + if (g_strcmp0 (nm_ip4_config_get_nis_domain (src), nm_ip4_config_get_nis_domain (dst)) == 0) + nm_ip4_config_set_nis_domain (dst, NULL); + + /* WINS */ + for (i = 0; i < nm_ip4_config_get_num_wins (src); i++) { + guint32 src_wins = nm_ip4_config_get_wins (src, i); + + for (j = 0; j < nm_ip4_config_get_num_wins (dst); j++) { + guint32 dst_wins = nm_ip4_config_get_wins (dst, j); + + if (dst_wins == src_wins) { + nm_ip4_config_del_wins (dst, j); + break; + } + } + } +} + gboolean nm_ip4_config_destination_is_direct (NMIP4Config *config, guint32 network, int plen) { @@ -467,6 +597,16 @@ nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new) g_array_append_val (priv->addresses, *new); } +void +nm_ip4_config_del_address (NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->addresses->len); + + g_array_remove_index (priv->addresses, i); +} + guint nm_ip4_config_get_num_addresses (NMIP4Config *config) { @@ -535,6 +675,31 @@ nm_ip4_config_take_route (NMIP4Config *config, NMIP4Route *route) nm_ip4_route_unref (route); } +void +nm_ip4_config_del_route (NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + GSList *iter, *last = priv->routes; + guint n; + + if (i == 0) { + last = priv->routes; + priv->routes = last->next; + last->next = NULL; + g_slist_free_full (last, (GDestroyNotify) nm_ip4_route_unref); + } else { + for (iter = priv->routes->next, n = 1, last = NULL; iter; iter = iter->next, n++) { + if (n == i) { + last->next = iter->next; + iter->next = NULL; + g_slist_free_full (iter, (GDestroyNotify) nm_ip4_route_unref); + break; + } + last = iter; + } + } +} + guint nm_ip4_config_get_num_routes (NMIP4Config *config) { @@ -576,6 +741,16 @@ nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 new) g_array_append_val (priv->nameservers, new); } +void +nm_ip4_config_del_nameserver (NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->nameservers->len); + + g_array_remove_index (priv->nameservers, i); +} + guint32 nm_ip4_config_get_num_nameservers (NMIP4Config *config) { @@ -618,6 +793,16 @@ nm_ip4_config_add_domain (NMIP4Config *config, const char *domain) g_ptr_array_add (priv->domains, g_strdup (domain)); } +void +nm_ip4_config_del_domain (NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->domains->len); + + g_ptr_array_remove_index (priv->domains, i); +} + guint32 nm_ip4_config_get_num_domains (NMIP4Config *config) { @@ -660,6 +845,16 @@ nm_ip4_config_add_search (NMIP4Config *config, const char *new) g_ptr_array_add (priv->searches, g_strdup (new)); } +void +nm_ip4_config_del_search (NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->searches->len); + + g_ptr_array_remove_index (priv->searches, i); +} + guint32 nm_ip4_config_get_num_searches (NMIP4Config *config) { @@ -735,6 +930,16 @@ nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis) g_array_append_val (priv->nis, nis); } +void +nm_ip4_config_del_nis_server (NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->nis->len); + + g_array_remove_index (priv->nis, i); +} + guint32 nm_ip4_config_get_num_nis_servers (NMIP4Config *config) { @@ -793,6 +998,16 @@ nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins) g_array_append_val (priv->wins, wins); } +void +nm_ip4_config_del_wins (NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->wins->len); + + g_array_remove_index (priv->wins, i); +} + guint32 nm_ip4_config_get_num_wins (NMIP4Config *config) { diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index f441be86c4..adef22e8c3 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -65,6 +65,7 @@ void nm_ip4_config_update_setting (NMIP4Config *config, NMSettingIP4Config *sett /* Utility functions */ void nm_ip4_config_merge (NMIP4Config *dst, NMIP4Config *src); +void nm_ip4_config_subtract (NMIP4Config *dst, NMIP4Config *src); gboolean nm_ip4_config_destination_is_direct (NMIP4Config *config, guint32 dest, int plen); /* Gateways */ @@ -76,6 +77,7 @@ guint32 nm_ip4_config_get_gateway (NMIP4Config *config); /* Addresses */ void nm_ip4_config_reset_addresses (NMIP4Config *config); void nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *address); +void nm_ip4_config_del_address (NMIP4Config *config, guint i); guint nm_ip4_config_get_num_addresses (NMIP4Config *config); const NMPlatformIP4Address *nm_ip4_config_get_address (NMIP4Config *config, guint i); @@ -83,24 +85,28 @@ const NMPlatformIP4Address *nm_ip4_config_get_address (NMIP4Config *config, guin void nm_ip4_config_reset_routes (NMIP4Config *config); void nm_ip4_config_add_route (NMIP4Config *config, NMIP4Route *route); void nm_ip4_config_take_route (NMIP4Config *config, NMIP4Route *route); +void nm_ip4_config_del_route (NMIP4Config *config, guint i); guint32 nm_ip4_config_get_num_routes (NMIP4Config *config); NMIP4Route * nm_ip4_config_get_route (NMIP4Config *config, guint32 i); /* Nameservers */ void nm_ip4_config_reset_nameservers (NMIP4Config *config); void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver); +void nm_ip4_config_del_nameserver (NMIP4Config *config, guint i); guint32 nm_ip4_config_get_num_nameservers (NMIP4Config *config); guint32 nm_ip4_config_get_nameserver (NMIP4Config *config, guint i); /* Domains */ void nm_ip4_config_reset_domains (NMIP4Config *config); void nm_ip4_config_add_domain (NMIP4Config *config, const char *domain); +void nm_ip4_config_del_domain (NMIP4Config *config, guint i); guint32 nm_ip4_config_get_num_domains (NMIP4Config *config); const char * nm_ip4_config_get_domain (NMIP4Config *config, guint i); /* Search lists */ void nm_ip4_config_reset_searches (NMIP4Config *config); void nm_ip4_config_add_search (NMIP4Config *config, const char *search); +void nm_ip4_config_del_search (NMIP4Config *config, guint i); guint32 nm_ip4_config_get_num_searches (NMIP4Config *config); const char * nm_ip4_config_get_search (NMIP4Config *config, guint i); @@ -115,6 +121,7 @@ guint32 nm_ip4_config_get_ptp_address (NMIP4Config *config); /* NIS */ void nm_ip4_config_reset_nis_servers (NMIP4Config *config); void nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis); +void nm_ip4_config_del_nis_server (NMIP4Config *config, guint i); guint32 nm_ip4_config_get_num_nis_servers (NMIP4Config *config); guint32 nm_ip4_config_get_nis_server (NMIP4Config *config, guint i); void nm_ip4_config_set_nis_domain (NMIP4Config *config, const char *domain); @@ -123,6 +130,7 @@ const char * nm_ip4_config_get_nis_domain (NMIP4Config *config); /* WINS */ void nm_ip4_config_reset_wins (NMIP4Config *config); void nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins); +void nm_ip4_config_del_wins (NMIP4Config *config, guint i); guint32 nm_ip4_config_get_num_wins (NMIP4Config *config); guint32 nm_ip4_config_get_wins (NMIP4Config *config, guint i); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index cb972c8d7d..2132b38fb4 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -11,7 +11,8 @@ INCLUDES = \ noinst_PROGRAMS = \ test-dhcp-options \ test-policy-hosts \ - test-wifi-ap-utils + test-wifi-ap-utils \ + test-ip4-config ####### DHCP options test ####### @@ -50,13 +51,26 @@ test_wifi_ap_utils_CPPFLAGS = \ test_wifi_ap_utils_LDADD = \ $(top_builddir)/src/libNetworkManager.la +####### ip4 config test ####### + +test_ip4_config_SOURCES = \ + test-ip4-config.c + +test_ip4_config_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) + +test_ip4_config_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + ####### secret agent interface test ####### EXTRA_DIST = test-secret-agent.py ########################################### -check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils +check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils test-ip4-config $(abs_builddir)/test-dhcp-options $(abs_builddir)/test-policy-hosts $(abs_builddir)/test-wifi-ap-utils + $(abs_builddir)/test-ip4-config diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c new file mode 100644 index 0000000000..373bf2eee2 --- /dev/null +++ b/src/tests/test-ip4-config.c @@ -0,0 +1,189 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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 +#include + +#include "nm-ip4-config.h" + +static void +addr_init (NMPlatformIP4Address *a, const char *addr, guint plen) +{ + memset (a, 0, sizeof (*a)); + g_assert (inet_pton (AF_INET, addr, (void *) &a->address) == 1); + a->plen = plen; +} + +static NMIP4Route * +route_new (const char *network, guint plen, const char *gw) +{ + NMIP4Route *route; + guint n; + + route = nm_ip4_route_new (); + g_assert (inet_pton (AF_INET, network, (void *) &n) == 1); + nm_ip4_route_set_dest (route, n); + nm_ip4_route_set_prefix (route, plen); + if (gw) { + n = 0; + g_assert (inet_pton (AF_INET, gw, (void *) &n) == 1); + nm_ip4_route_set_next_hop (route, n); + } + return route; +} + +static guint32 +addr_to_num (const char *addr) +{ + guint n; + + g_assert (inet_pton (AF_INET, addr, (void *) &n) == 1); + return n; +} + +static NMIP4Config * +build_test_config (void) +{ + NMIP4Config *config; + NMPlatformIP4Address addr; + NMIP4Route *route; + + /* Build up the config to subtract */ + config = nm_ip4_config_new (); + + addr_init (&addr, "192.168.1.10", 24); + nm_ip4_config_add_address (config, &addr); + + route = route_new ("10.0.0.0", 8, "192.168.1.1"); + nm_ip4_config_take_route (config, route); + + route = route_new ("172.16.0.0", 16, "192.168.1.1"); + nm_ip4_config_take_route (config, route); + + nm_ip4_config_set_gateway (config, addr_to_num ("192.168.1.1")); + + nm_ip4_config_add_nameserver (config, addr_to_num ("4.2.2.1")); + nm_ip4_config_add_nameserver (config, addr_to_num ("4.2.2.2")); + nm_ip4_config_add_domain (config, "foobar.com"); + nm_ip4_config_add_domain (config, "baz.com"); + nm_ip4_config_add_search (config, "blahblah.com"); + nm_ip4_config_add_search (config, "beatbox.com"); + + nm_ip4_config_set_ptp_address (config, addr_to_num ("1.2.3.4")); + + nm_ip4_config_add_nis_server (config, addr_to_num ("1.2.3.9")); + nm_ip4_config_add_nis_server (config, addr_to_num ("1.2.3.10")); + + nm_ip4_config_add_wins (config, addr_to_num ("4.2.3.9")); + nm_ip4_config_add_wins (config, addr_to_num ("4.2.3.10")); + + return config; +} + +static void +test_subtract (void) +{ + NMIP4Config *src, *dst; + NMPlatformIP4Address addr; + const NMPlatformIP4Address *test_addr; + NMIP4Route *route; + const char *expected_addr = "192.168.1.12"; + guint32 expected_addr_plen = 24; + const char *expected_route_dest = "8.7.6.5"; + guint32 expected_route_plen = 8; + const char *expected_route_next_hop = "192.168.1.1"; + guint32 expected_ns1 = addr_to_num ("8.8.8.8"); + guint32 expected_ns2 = addr_to_num ("8.8.8.9"); + const char *expected_domain = "wonderfalls.com"; + const char *expected_search = "somewhere.com"; + guint32 expected_nis = addr_to_num ("1.2.3.13"); + guint32 expected_wins = addr_to_num ("2.3.4.5"); + + src = build_test_config (); + + /* add a couple more things to the test config */ + dst = build_test_config (); + addr_init (&addr, expected_addr, expected_addr_plen); + nm_ip4_config_add_address (dst, &addr); + + route = route_new (expected_route_dest, expected_route_plen, expected_route_next_hop); + nm_ip4_config_take_route (dst, route); + + nm_ip4_config_add_nameserver (dst, expected_ns1); + nm_ip4_config_add_nameserver (dst, expected_ns2); + nm_ip4_config_add_domain (dst, expected_domain); + nm_ip4_config_add_search (dst, expected_search); + + nm_ip4_config_add_nis_server (dst, expected_nis); + nm_ip4_config_add_wins (dst, expected_wins); + + nm_ip4_config_subtract (dst, src); + + /* ensure what's left is what we expect */ + g_assert_cmpuint (nm_ip4_config_get_num_addresses (dst), ==, 1); + test_addr = nm_ip4_config_get_address (dst, 0); + g_assert (test_addr != NULL); + g_assert_cmpuint (test_addr->address, ==, addr_to_num (expected_addr)); + g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen); + + g_assert_cmpuint (nm_ip4_config_get_ptp_address (dst), ==, 0); + g_assert_cmpuint (nm_ip4_config_get_gateway (dst), ==, 0); + + g_assert_cmpuint (nm_ip4_config_get_num_routes (dst), ==, 1); + route = nm_ip4_config_get_route (dst, 0); + g_assert (route != NULL); + g_assert_cmpuint (nm_ip4_route_get_dest (route), ==, addr_to_num (expected_route_dest)); + g_assert_cmpuint (nm_ip4_route_get_prefix (route), ==, expected_route_plen); + g_assert_cmpuint (nm_ip4_route_get_next_hop (route), ==, addr_to_num (expected_route_next_hop)); + + g_assert_cmpuint (nm_ip4_config_get_num_nameservers (dst), ==, 2); + g_assert_cmpuint (nm_ip4_config_get_nameserver (dst, 0), ==, expected_ns1); + g_assert_cmpuint (nm_ip4_config_get_nameserver (dst, 1), ==, expected_ns2); + + g_assert_cmpuint (nm_ip4_config_get_num_domains (dst), ==, 1); + g_assert_cmpstr (nm_ip4_config_get_domain (dst, 0), ==, expected_domain); + g_assert_cmpuint (nm_ip4_config_get_num_searches (dst), ==, 1); + g_assert_cmpstr (nm_ip4_config_get_search (dst, 0), ==, expected_search); + + g_assert_cmpuint (nm_ip4_config_get_num_nis_servers (dst), ==, 1); + g_assert_cmpuint (nm_ip4_config_get_nis_server (dst, 0), ==, expected_nis); + + g_assert_cmpuint (nm_ip4_config_get_num_wins (dst), ==, 1); + g_assert_cmpuint (nm_ip4_config_get_wins (dst, 0), ==, expected_wins); + + g_object_unref (src); + g_object_unref (dst); +} + +/*******************************************/ + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_type_init (); + + g_test_add_func ("/ip4-config/subtract", test_subtract); + + return g_test_run (); +} +