diff options
author | Dan Williams <dcbw@redhat.com> | 2014-07-01 10:26:01 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2014-07-22 14:39:19 -0500 |
commit | 31d19f51d1e8fa4e2df47d45f41e716acab2286a (patch) | |
tree | cfff594fd59869e1349b4884666ce07046f81bf8 | |
parent | 4ce6e39a8f07994f12d7170c554b60327d117a82 (diff) | |
download | NetworkManager-31d19f51d1e8fa4e2df47d45f41e716acab2286a.tar.gz |
dhcp: filter DHCP options when setting them
Don't bother storing all the options, only store the ones we care
about and ones we export through the NMDHCP4Config and NMDHCP6Config
objects.
-rw-r--r-- | src/devices/nm-device.c | 12 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-client.c | 78 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-client.h | 6 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-utils.c | 46 | ||||
-rw-r--r-- | src/dhcp-manager/tests/test-dhcp-options.c | 68 |
5 files changed, 102 insertions, 108 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index d1b34b25ae..658b58b28d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2604,11 +2604,9 @@ dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release) } static void -dhcp4_add_option_cb (gpointer key, gpointer value, gpointer user_data) +dhcp4_add_option_cb (const char *key, const char *value, gpointer user_data) { - nm_dhcp4_config_add_option (NM_DHCP4_CONFIG (user_data), - (const char *) key, - (const char *) value); + nm_dhcp4_config_add_option (NM_DHCP4_CONFIG (user_data), key, value); } static gboolean @@ -3023,11 +3021,9 @@ dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release) } static void -dhcp6_add_option_cb (gpointer key, gpointer value, gpointer user_data) +dhcp6_add_option_cb (const char *key, const char *value, gpointer user_data) { - nm_dhcp6_config_add_option (NM_DHCP6_CONFIG (user_data), - (const char *) key, - (const char *) value); + nm_dhcp6_config_add_option (NM_DHCP6_CONFIG (user_data), key, value); } static gboolean diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 6d18dd1b91..4cfe08d4a7 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -596,25 +596,47 @@ garray_to_string (GArray *array, const char *key) return converted; } +#define OLD_TAG "old_" +#define NEW_TAG "new_" + static void -copy_option (gpointer key, - gpointer value, +copy_option (const char * key, + GValue *value, gpointer user_data) { GHashTable *hash = user_data; - const char *str_key = (const char *) key; char *str_value = NULL; + const char **p; + static const char *ignored_keys[] = { + "interface", + "pid", + "reason", + "dhcp_message_type", + NULL + }; + + if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY)) { + nm_log_warn (LOGD_DHCP, "key %s value type was not DBUS_TYPE_G_UCHAR_ARRAY", key); + return; + } - if (G_VALUE_TYPE (value) != DBUS_TYPE_G_UCHAR_ARRAY) { - nm_log_warn (LOGD_DHCP, "unexpected key %s value type was not " - "DBUS_TYPE_G_UCHAR_ARRAY", - str_key); + if (g_str_has_prefix (key, OLD_TAG)) return; + + /* Filter out stuff that's not actually new DHCP options */ + for (p = ignored_keys; *p; p++) { + if (!strcmp (*p, key)) + return; } - str_value = garray_to_string ((GArray *) g_value_get_boxed (value), str_key); + if (g_str_has_prefix (key, NEW_TAG)) + key += STRLEN (NEW_TAG); + if (!key[0]) + return; + + str_value = garray_to_string ((GArray *) g_value_get_boxed (value), key); if (str_value) - g_hash_table_insert (hash, g_strdup (str_key), str_value); + g_hash_table_insert (hash, g_strdup (key), str_value); } void @@ -636,7 +658,7 @@ nm_dhcp_client_new_options (NMDHCPClient *self, /* Clear old and save new DHCP options */ g_hash_table_remove_all (priv->options); - g_hash_table_foreach (options, copy_option, priv->options); + g_hash_table_foreach (options, (GHFunc) copy_option, priv->options); /* dhclient sends same-state transitions for RENEW/REBIND events, but * the lease may have changed, so handle same-state transitions for @@ -661,20 +683,17 @@ nm_dhcp_client_new_options (NMDHCPClient *self, nm_dhcp_client_set_state (self, new_state); } -#define NEW_TAG "new_" -#define OLD_TAG "old_" - gboolean nm_dhcp_client_foreach_option (NMDHCPClient *self, - GHFunc func, + NMDhcpClientForeachFunc callback, gpointer user_data) { NMDHCPClientPrivate *priv; GHashTableIter iter; - gpointer iterkey, itervalue; + const char *key, *value; g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); - g_return_val_if_fail (func != NULL, FALSE); + g_return_val_if_fail (callback != NULL, FALSE); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -686,32 +705,9 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self, } g_hash_table_iter_init (&iter, priv->options); - while (g_hash_table_iter_next (&iter, &iterkey, &itervalue)) { - const char *key = iterkey, *value = itervalue; - const char **p; - static const char *filter_options[] = { - "interface", "pid", "reason", "dhcp_message_type", NULL - }; - gboolean ignore = FALSE; - - /* Filter out stuff that's not actually new DHCP options */ - for (p = filter_options; *p; p++) { - if (!strcmp (*p, key) || !strncmp (key, OLD_TAG, strlen (OLD_TAG))) { - ignore = TRUE; - break; - } - } + while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) + callback (key, value, user_data); - if (!ignore) { - const char *tmp_key = key; - - /* Remove the "new_" prefix that dhclient passes back */ - if (!strncmp (key, NEW_TAG, strlen (NEW_TAG))) - tmp_key = key + strlen (NEW_TAG); - - func ((gpointer) tmp_key, (gpointer) value, user_data); - } - } return TRUE; } diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index 89cd7cc045..0fe8643c86 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -121,8 +121,12 @@ void nm_dhcp_client_new_options (NMDHCPClient *self, GHashTable *options, const char *reason); +typedef void (*NMDhcpClientForeachFunc) (const char *key, + const char *value, + gpointer user_data); + gboolean nm_dhcp_client_foreach_option (NMDHCPClient *self, - GHFunc func, + NMDhcpClientForeachFunc callback, gpointer user_data); /* Backend helpers for subclasses */ diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c index 0e12714a8b..60f0ab9030 100644 --- a/src/dhcp-manager/nm-dhcp-utils.c +++ b/src/dhcp-manager/nm-dhcp-utils.c @@ -232,7 +232,7 @@ ip4_process_classless_routes (GHashTable *options, * * 192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41 */ - str = g_hash_table_lookup (options, "new_classless_static_routes"); + str = g_hash_table_lookup (options, "classless_static_routes"); /* dhclient doesn't have actual support for rfc3442 classless static routes * upstream. Thus, people resort to defining the option in dhclient.conf @@ -243,11 +243,11 @@ ip4_process_classless_routes (GHashTable *options, * See https://lists.isc.org/pipermail/dhcp-users/2008-December/007629.html */ if (!str) - str = g_hash_table_lookup (options, "new_rfc3442_classless_static_routes"); + str = g_hash_table_lookup (options, "rfc3442_classless_static_routes"); /* Microsoft version; same as rfc3442 but with a different option # (249) */ if (!str) - str = g_hash_table_lookup (options, "new_ms_classless_static_routes"); + str = g_hash_table_lookup (options, "ms_classless_static_routes"); if (!str || !strlen (str)) return FALSE; @@ -275,7 +275,7 @@ process_classful_routes (GHashTable *options, guint priority, NMIP4Config *ip4_c const char *str; char **searches, **s; - str = g_hash_table_lookup (options, "new_static_routes"); + str = g_hash_table_lookup (options, "static_routes"); if (!str) return; @@ -386,14 +386,14 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, memset (&address, 0, sizeof (address)); address.timestamp = nm_utils_get_monotonic_timestamp_s (); - str = g_hash_table_lookup (options, "new_ip_address"); + str = g_hash_table_lookup (options, "ip_address"); if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) { address.address = tmp_addr; nm_log_info (LOGD_DHCP4, " address %s", str); } else goto error; - str = g_hash_table_lookup (options, "new_subnet_mask"); + str = g_hash_table_lookup (options, "subnet_mask"); if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) { plen = nm_utils_ip4_netmask_to_prefix (tmp_addr); nm_log_info (LOGD_DHCP4, " plen %d (%s)", plen, str); @@ -417,7 +417,7 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, /* If the gateway wasn't provided as a classless static route with a * subnet length of 0, try to find it using the old-style 'routers' option. */ - str = g_hash_table_lookup (options, "new_routers"); + str = g_hash_table_lookup (options, "routers"); if (str) { char **routers = g_strsplit (str, " ", 0); char **s; @@ -447,7 +447,7 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, * dhcp server may not be reachable via unicast, and a host * specific route is needed. **/ - str = g_hash_table_lookup (options, "new_dhcp_server_identifier"); + str = g_hash_table_lookup (options, "dhcp_server_identifier"); if (str) { if (inet_pton (AF_INET, str, &tmp_addr) > 0) { NMPlatformIP4Route route; @@ -472,7 +472,7 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, nm_log_warn (LOGD_DHCP4, "ignoring invalid server identifier '%s'", str); } - str = g_hash_table_lookup (options, "new_dhcp_lease_time"); + str = g_hash_table_lookup (options, "dhcp_lease_time"); if (str) { address.lifetime = address.preferred = strtoul (str, NULL, 10); nm_log_info (LOGD_DHCP4, " lease time %d", address.lifetime); @@ -481,11 +481,11 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, address.source = NM_PLATFORM_SOURCE_DHCP; nm_ip4_config_add_address (ip4_config, &address); - str = g_hash_table_lookup (options, "new_host_name"); + str = g_hash_table_lookup (options, "host_name"); if (str) nm_log_info (LOGD_DHCP4, " hostname '%s'", str); - str = g_hash_table_lookup (options, "new_domain_name_servers"); + str = g_hash_table_lookup (options, "domain_name_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; @@ -500,7 +500,7 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, g_strfreev (searches); } - str = g_hash_table_lookup (options, "new_domain_name"); + str = g_hash_table_lookup (options, "domain_name"); if (str) { char **domains = g_strsplit (str, " ", 0); char **s; @@ -512,11 +512,11 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, g_strfreev (domains); } - str = g_hash_table_lookup (options, "new_domain_search"); + str = g_hash_table_lookup (options, "domain_search"); if (str) process_domain_search (str, ip4_add_domain_search, ip4_config); - str = g_hash_table_lookup (options, "new_netbios_name_servers"); + str = g_hash_table_lookup (options, "netbios_name_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; @@ -531,7 +531,7 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, g_strfreev (searches); } - str = g_hash_table_lookup (options, "new_interface_mtu"); + str = g_hash_table_lookup (options, "interface_mtu"); if (str) { int int_mtu; @@ -544,13 +544,13 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, nm_ip4_config_set_mtu (ip4_config, int_mtu); } - str = g_hash_table_lookup (options, "new_nis_domain"); + str = g_hash_table_lookup (options, "nis_domain"); if (str) { nm_log_info (LOGD_DHCP4, " NIS domain '%s'", str); nm_ip4_config_set_nis_domain (ip4_config, str); } - str = g_hash_table_lookup (options, "new_nis_servers"); + str = g_hash_table_lookup (options, "nis_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; @@ -607,19 +607,19 @@ nm_dhcp_utils_ip6_config_from_options (const char *iface, ip6_config = nm_ip6_config_new (); - str = g_hash_table_lookup (options, "new_max_life"); + str = g_hash_table_lookup (options, "max_life"); if (str) { address.lifetime = strtoul (str, NULL, 10); nm_log_info (LOGD_DHCP6, " valid_lft %d", address.lifetime); } - str = g_hash_table_lookup (options, "new_preferred_life"); + str = g_hash_table_lookup (options, "preferred_life"); if (str) { address.preferred = strtoul (str, NULL, 10); nm_log_info (LOGD_DHCP6, " preferred_lft %d", address.preferred); } - str = g_hash_table_lookup (options, "new_ip6_address"); + str = g_hash_table_lookup (options, "ip6_address"); if (str) { if (!inet_pton (AF_INET6, str, &tmp_addr)) { nm_log_warn (LOGD_DHCP6, "(%s): DHCP returned invalid address '%s'", @@ -636,11 +636,11 @@ nm_dhcp_utils_ip6_config_from_options (const char *iface, goto error; } - str = g_hash_table_lookup (options, "new_host_name"); + str = g_hash_table_lookup (options, "host_name"); if (str) nm_log_info (LOGD_DHCP6, " hostname '%s'", str); - str = g_hash_table_lookup (options, "new_dhcp6_name_servers"); + str = g_hash_table_lookup (options, "dhcp6_name_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; @@ -655,7 +655,7 @@ nm_dhcp_utils_ip6_config_from_options (const char *iface, g_strfreev (searches); } - str = g_hash_table_lookup (options, "new_dhcp6_domain_search"); + str = g_hash_table_lookup (options, "dhcp6_domain_search"); if (str) process_domain_search (str, ip6_add_domain_search, ip6_config); diff --git a/src/dhcp-manager/tests/test-dhcp-options.c b/src/dhcp-manager/tests/test-dhcp-options.c index 0fa82da17c..e3a6762944 100644 --- a/src/dhcp-manager/tests/test-dhcp-options.c +++ b/src/dhcp-manager/tests/test-dhcp-options.c @@ -47,23 +47,21 @@ fill_table (Option *test_options, GHashTable *table) } static Option generic_options[] = { - { "new_subnet_mask", "255.255.255.0" }, - { "new_ip_address", "192.168.1.106" }, - { "new_network_number", "192.168.1.0" }, - { "interface", "eth0" }, - { "reason", "BOUND" }, - { "new_expiry", "1232324877" }, - { "new_dhcp_lease_time", "3600" }, - { "new_dhcp_server_identifier", "192.168.1.1" }, - { "new_routers", "192.168.1.1" }, - { "new_domain_name_servers", "216.254.95.2 216.231.41.2" }, - { "new_dhcp_message_type", "5" }, - { "new_broadcast_address", "192.168.1.255" }, - { "new_domain_search", "foobar.com blah.foobar.com" }, - { "new_host_name", "nmreallywhipsthe" }, - { "new_domain_name", "lamasass.com" }, - { "new_interface_mtu", "987" }, - { "new_static_routes", "10.1.1.5 10.1.1.1 100.99.88.56 10.1.1.1" }, + { "subnet_mask", "255.255.255.0" }, + { "ip_address", "192.168.1.106" }, + { "network_number", "192.168.1.0" }, + { "expiry", "1232324877" }, + { "dhcp_lease_time", "3600" }, + { "dhcp_server_identifier", "192.168.1.1" }, + { "routers", "192.168.1.1" }, + { "domain_name_servers", "216.254.95.2 216.231.41.2" }, + { "dhcp_message_type", "5" }, + { "broadcast_address", "192.168.1.255" }, + { "domain_search", "foobar.com blah.foobar.com" }, + { "host_name", "nmreallywhipsthe" }, + { "domain_name", "lamasass.com" }, + { "interface_mtu", "987" }, + { "static_routes", "10.1.1.5 10.1.1.1 100.99.88.56 10.1.1.1" }, { NULL, NULL } }; @@ -180,7 +178,7 @@ test_generic_options (void) } static Option wins_options[] = { - { "new_netbios_name_servers", "63.12.199.5 150.4.88.120" }, + { "netbios_name_servers", "63.12.199.5 150.4.88.120" }, { NULL, NULL } }; @@ -275,7 +273,7 @@ test_classless_static_routes_1 (void) const char *expected_route2_gw = "10.17.66.41"; static Option data[] = { /* dhclient custom format */ - { "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41" }, + { "rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41" }, { NULL, NULL } }; @@ -307,7 +305,7 @@ test_classless_static_routes_2 (void) const char *expected_route2_gw = "10.17.66.41"; static Option data[] = { /* dhcpcd format */ - { "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41" }, + { "classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41" }, { NULL, NULL } }; @@ -340,7 +338,7 @@ test_fedora_dhclient_classless_static_routes (void) const char *expected_gateway = "192.168.0.113"; static Option data[] = { /* Fedora dhclient format */ - { "new_classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6" }, + { "classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6" }, { NULL, NULL } }; @@ -373,7 +371,7 @@ test_dhclient_invalid_classless_routes_1 (void) const char *expected_route1_gw = "192.168.1.1"; static Option data[] = { /* dhclient format */ - { "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41" }, + { "rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41" }, { NULL, NULL } }; @@ -408,7 +406,7 @@ test_dhcpcd_invalid_classless_routes_1 (void) const char *expected_route2_gw = "10.1.1.1"; static Option data[] = { /* dhcpcd format */ - { "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41" }, + { "classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41" }, { NULL, NULL } }; @@ -445,7 +443,7 @@ test_dhclient_invalid_classless_routes_2 (void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; static Option data[] = { - { "new_rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1" }, + { "rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1" }, { NULL, NULL } }; @@ -482,7 +480,7 @@ test_dhcpcd_invalid_classless_routes_2 (void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; static Option data[] = { - { "new_classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1" }, + { "classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1" }, { NULL, NULL } }; @@ -519,7 +517,7 @@ test_dhclient_invalid_classless_routes_3 (void) const char *expected_route1_dest = "192.168.10.0"; const char *expected_route1_gw = "192.168.1.1"; static Option data[] = { - { "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41" }, + { "rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41" }, { NULL, NULL } }; @@ -550,7 +548,7 @@ test_dhcpcd_invalid_classless_routes_3 (void) const char *expected_route1_dest = "192.168.10.0"; const char *expected_route1_gw = "192.168.1.1"; static Option data[] = { - { "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41" }, + { "classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41" }, { NULL, NULL } }; @@ -582,7 +580,7 @@ test_dhclient_gw_in_classless_routes (void) const char *expected_route1_gw = "192.168.1.1"; const char *expected_gateway = "192.2.3.4"; static Option data[] = { - { "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4" }, + { "rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4" }, { NULL, NULL } }; @@ -613,7 +611,7 @@ test_dhcpcd_gw_in_classless_routes (void) const char *expected_route1_gw = "192.168.1.1"; const char *expected_gateway = "192.2.3.4"; static Option data[] = { - { "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4" }, + { "classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4" }, { NULL, NULL } }; @@ -636,7 +634,7 @@ test_dhcpcd_gw_in_classless_routes (void) } static Option escaped_searches_options[] = { - { "new_domain_search", "host1\\032host2\\032host3" }, + { "domain_search", "host1\\032host2\\032host3" }, { NULL, NULL } }; @@ -669,7 +667,7 @@ test_escaped_domain_searches (void) } static Option invalid_escaped_searches_options[] = { - { "new_domain_search", "host1\\aahost2\\032host3" }, + { "domain_search", "host1\\aahost2\\032host3" }, { NULL, NULL } }; @@ -704,8 +702,8 @@ test_ip4_missing_prefix (const char *ip, guint32 expected_prefix) const NMPlatformIP4Address *address; options = fill_table (generic_options, NULL); - g_hash_table_insert (options, "new_ip_address", (gpointer) ip); - g_hash_table_remove (options, "new_subnet_mask"); + g_hash_table_insert (options, "ip_address", (gpointer) ip); + g_hash_table_remove (options, "subnet_mask"); ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); ASSERT (ip4_config != NULL, @@ -756,8 +754,8 @@ test_ip4_prefix_classless (void) */ options = fill_table (generic_options, NULL); - g_hash_table_insert (options, "new_ip_address", "172.16.54.22"); - g_hash_table_insert (options, "new_subnet_mask", "255.255.252.0"); + g_hash_table_insert (options, "ip_address", "172.16.54.22"); + g_hash_table_insert (options, "subnet_mask", "255.255.252.0"); ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); ASSERT (ip4_config != NULL, |