summary refs log tree commit diff
path: root/src/dhcp-manager
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhcp-manager')
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c21
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.c2
-rw-r--r--src/dhcp-manager/nm-dhcp-systemd.c7
-rw-r--r--src/dhcp-manager/nm-dhcp-utils.c3
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h2
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h1
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c52
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h1
-rw-r--r--src/dhcp-manager/tests/test-dhcp-utils.c60
9 files changed, 128 insertions, 21 deletions
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index eb317330..7f5d5a28 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -36,6 +36,7 @@
 #include "nm-dhcp-client.h"
 #include "nm-dhcp-utils.h"
 #include "nm-platform.h"
+#include "gsystem-local-alloc.h"
 
 typedef struct {
 	char *       iface;
@@ -284,6 +285,7 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
                           GHashTable *options)
 {
 	NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
+	gs_free char *event_id = NULL;
 
 	if (new_state >= NM_DHCP_STATE_BOUND)
 		timeout_cleanup (self);
@@ -308,19 +310,30 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
 	if ((priv->state == new_state) && (new_state != NM_DHCP_STATE_BOUND))
 		return;
 
+	if (priv->ipv6 && new_state == NM_DHCP_STATE_BOUND) {
+		char *start, *iaid;
+
+		iaid = g_hash_table_lookup (options, "iaid");
+		start = g_hash_table_lookup (options, "life_starts");
+		if (iaid && start)
+			event_id = g_strdup_printf ("%s|%s", iaid, start);
+	}
+
 	nm_log_info (priv->ipv6 ? LOGD_DHCP6 : LOGD_DHCP4,
-	             "(%s): DHCPv%c state changed %s -> %s",
+	             "(%s): DHCPv%c state changed %s -> %s%s%s%s",
 	             priv->iface,
 	             priv->ipv6 ? '6' : '4',
 	             state_to_string (priv->state),
-	             state_to_string (new_state));
+	             state_to_string (new_state),
+	             NM_PRINT_FMT_QUOTED (event_id, ", event ID=\"", event_id, "\"", ""));
 
 	priv->state = new_state;
 	g_signal_emit (G_OBJECT (self),
 	               signals[SIGNAL_STATE_CHANGED], 0,
 	               new_state,
 	               ip_config,
-	               options);
+	               options,
+	               event_id);
 }
 
 static gboolean
@@ -977,6 +990,6 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
 					  G_SIGNAL_RUN_FIRST,
 					  G_STRUCT_OFFSET (NMDhcpClientClass, state_changed),
 					  NULL, NULL, NULL,
-					  G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_HASH_TABLE);
+					  G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_HASH_TABLE, G_TYPE_STRING);
 }
 
diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c
index f936f45c..20ddefc3 100644
--- a/src/dhcp-manager/nm-dhcp-manager.c
+++ b/src/dhcp-manager/nm-dhcp-manager.c
@@ -184,6 +184,7 @@ static void client_state_changed (NMDhcpClient *client,
                                   NMDhcpState state,
                                   GObject *ip_config,
                                   GHashTable *options,
+                                  const char *event_id,
                                   NMDhcpManager *self);
 
 static void
@@ -204,6 +205,7 @@ client_state_changed (NMDhcpClient *client,
                       NMDhcpState state,
                       GObject *ip_config,
                       GHashTable *options,
+                      const char *event_id,
                       NMDhcpManager *self)
 {
 	if (state >= NM_DHCP_STATE_TIMEOUT)
diff --git a/src/dhcp-manager/nm-dhcp-systemd.c b/src/dhcp-manager/nm-dhcp-systemd.c
index 12dc03cc..2bd0d72f 100644
--- a/src/dhcp-manager/nm-dhcp-systemd.c
+++ b/src/dhcp-manager/nm-dhcp-systemd.c
@@ -224,6 +224,8 @@ lease_to_ip4_config (sd_dhcp_lease *lease,
 	guint16 mtu;
 	int r, num;
 	guint64 end_time;
+	uint8_t *data;
+	gboolean metered = FALSE;
 
 	g_return_val_if_fail (lease != NULL, NULL);
 
@@ -355,6 +357,11 @@ lease_to_ip4_config (sd_dhcp_lease *lease,
 		g_string_free (l, TRUE);
 	}
 
+	num = sd_dhcp_lease_get_vendor_specific (lease, &data);
+	if (num > 0)
+		metered = !!memmem (data, num, "ANDROID_METERED", STRLEN ("ANDROID_METERED"));
+	nm_ip4_config_set_metered (ip4_config, metered);
+
 	return ip4_config;
 }
 
diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c
index 8cd4359a..ab7f26d5 100644
--- a/src/dhcp-manager/nm-dhcp-utils.c
+++ b/src/dhcp-manager/nm-dhcp-utils.c
@@ -575,6 +575,9 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface,
 		g_strfreev (nis);
 	}
 
+	str = g_hash_table_lookup (options, "vendor_encapsulated_options");
+	nm_ip4_config_set_metered (ip4_config, str && strstr (str, "ANDROID_METERED"));
+
 	return ip4_config;
 
 error:
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h
index 9e184ac4..71f7f143 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h
@@ -72,6 +72,8 @@ struct sd_dhcp_lease {
         char *root_path;
         uint8_t *client_id;
         size_t client_id_len;
+        uint8_t *vendor_specific;
+        size_t vendor_specific_size;
 };
 
 int dhcp_lease_new(sd_dhcp_lease **ret);
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h
index abca9422..aa37e9b0 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h
@@ -125,6 +125,7 @@ enum {
         DHCP_OPTION_BROADCAST                   = 28,
         DHCP_OPTION_STATIC_ROUTE                = 33,
         DHCP_OPTION_NTP_SERVER                  = 42,
+        DHCP_OPTION_VENDOR_SPECIFIC             = 43,
         DHCP_OPTION_REQUESTED_IP_ADDRESS        = 50,
         DHCP_OPTION_IP_ADDRESS_LEASE_TIME       = 51,
         DHCP_OPTION_OVERLOAD                    = 52,
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c
index 2d13d503..0b5048a6 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c
@@ -191,6 +191,19 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes
         return 0;
 }
 
+int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data) {
+        assert_return(lease, -EINVAL);
+        assert_return(data, -EINVAL);
+
+        if (lease->vendor_specific) {
+                *data = lease->vendor_specific;
+                return lease->vendor_specific_size;
+        } else
+                return -ENOENT;
+
+        return 0;
+}
+
 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
         if (lease)
                 assert_se(REFCNT_INC(lease->n_ref) >= 2);
@@ -286,6 +299,24 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
         return 0;
 }
 
+static int lease_parse_binary(const uint8_t *option, size_t len, uint8_t **ret) {
+        assert (option);
+        assert (ret);
+
+        if (len >= 1) {
+                uint8_t *data;
+
+                data = memdup(option, len);
+                if (!data)
+                        return -errno;
+
+                free(*ret);
+                *ret = data;
+        }
+
+        return 0;
+}
+
 static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
         assert(option);
         assert(ret);
@@ -568,6 +599,14 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
                         return r;
 
                 break;
+
+        case DHCP_OPTION_VENDOR_SPECIFIC:
+               r = lease_parse_binary(option, len, &lease->vendor_specific);
+               if (r < 0)
+                       return r;
+               lease->vendor_specific_size = len;
+
+               break;
         }
 
         return 0;
@@ -595,6 +634,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         const uint8_t *client_id;
         size_t client_id_len;
         const char *string;
+        uint8_t *data;
         uint16_t mtu;
         struct sd_dhcp_route *routes;
         int r;
@@ -667,6 +707,18 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         if (r >= 0)
                 serialize_dhcp_routes(f, "ROUTES", routes, r);
 
+        r = sd_dhcp_lease_get_vendor_specific(lease, &data);
+        if (r >= 0) {
+                _cleanup_free_ char *option_hex = NULL;
+
+                option_hex = hexmem(data, r);
+                if (!option_hex) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+                fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
+        }
+
         r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
         if (r >= 0) {
                 _cleanup_free_ char *client_id_hex = NULL;
diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h
index 4296b91d..079a1bb3 100644
--- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h
+++ b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h
@@ -45,6 +45,7 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn);
+int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data);
 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
                                 size_t *client_id_len);
 
diff --git a/src/dhcp-manager/tests/test-dhcp-utils.c b/src/dhcp-manager/tests/test-dhcp-utils.c
index 53688a5b..618188df 100644
--- a/src/dhcp-manager/tests/test-dhcp-utils.c
+++ b/src/dhcp-manager/tests/test-dhcp-utils.c
@@ -72,7 +72,7 @@ static void
 test_generic_options (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const NMPlatformIP4Address *address;
 	const NMPlatformIP4Route *route;
 	guint32 tmp;
@@ -147,7 +147,7 @@ static void
 test_wins_options (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const NMPlatformIP4Address *address;
 	guint32 tmp;
 	const char *expected_wins1 = "63.12.199.5";
@@ -176,6 +176,31 @@ test_wins_options (void)
 }
 
 static void
+test_vendor_option_metered (void)
+{
+	GHashTable *options;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
+	static const Option data[] = {
+		{ "vendor_encapsulated_options", "ANDROID_METERED" },
+		{ NULL, NULL }
+	};
+
+	options = fill_table (generic_options, NULL);
+	ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
+	g_assert (ip4_config);
+	g_assert (nm_ip4_config_get_metered (ip4_config) == FALSE);
+	g_hash_table_destroy (options);
+	g_clear_object (&ip4_config);
+
+	options = fill_table (generic_options, NULL);
+	options = fill_table (data, options);
+	ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
+	g_assert (ip4_config);
+	g_assert (nm_ip4_config_get_metered (ip4_config) == TRUE);
+	g_hash_table_destroy (options);
+}
+
+static void
 ip4_test_route (NMIP4Config *ip4_config,
                 guint route_num,
                 const char *expected_dest,
@@ -208,7 +233,7 @@ static void
 test_classless_static_routes_1 (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "192.168.10.0";
 	const char *expected_route1_gw = "192.168.1.1";
 	const char *expected_route2_dest = "10.0.0.0";
@@ -236,7 +261,7 @@ static void
 test_classless_static_routes_2 (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "192.168.10.0";
 	const char *expected_route1_gw = "192.168.1.1";
 	const char *expected_route2_dest = "10.0.0.0";
@@ -264,7 +289,7 @@ static void
 test_fedora_dhclient_classless_static_routes (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "129.210.177.128";
 	const char *expected_route1_gw = "192.168.0.113";
 	const char *expected_route2_dest = "2.0.0.0";
@@ -296,7 +321,7 @@ static void
 test_dhclient_invalid_classless_routes_1 (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "192.168.10.0";
 	const char *expected_route1_gw = "192.168.1.1";
 	static const Option data[] = {
@@ -325,7 +350,7 @@ static void
 test_dhcpcd_invalid_classless_routes_1 (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "10.1.1.5";
 	const char *expected_route1_gw = "10.1.1.1";
 	const char *expected_route2_dest = "100.99.88.56";
@@ -359,7 +384,7 @@ static void
 test_dhclient_invalid_classless_routes_2 (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "10.1.1.5";
 	const char *expected_route1_gw = "10.1.1.1";
 	const char *expected_route2_dest = "100.99.88.56";
@@ -392,7 +417,7 @@ static void
 test_dhcpcd_invalid_classless_routes_2 (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "10.1.1.5";
 	const char *expected_route1_gw = "10.1.1.1";
 	const char *expected_route2_dest = "100.99.88.56";
@@ -427,7 +452,7 @@ static void
 test_dhclient_invalid_classless_routes_3 (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "192.168.10.0";
 	const char *expected_route1_gw = "192.168.1.1";
 	static const Option data[] = {
@@ -455,7 +480,7 @@ static void
 test_dhcpcd_invalid_classless_routes_3 (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "192.168.10.0";
 	const char *expected_route1_gw = "192.168.1.1";
 	static Option data[] = {
@@ -483,7 +508,7 @@ static void
 test_dhclient_gw_in_classless_routes (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "192.168.10.0";
 	const char *expected_route1_gw = "192.168.1.1";
 	const char *expected_gateway = "192.2.3.4";
@@ -511,7 +536,7 @@ static void
 test_dhcpcd_gw_in_classless_routes (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_route1_dest = "192.168.10.0";
 	const char *expected_route1_gw = "192.168.1.1";
 	const char *expected_gateway = "192.2.3.4";
@@ -539,7 +564,7 @@ static void
 test_escaped_domain_searches (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const char *expected_search0 = "host1";
 	const char *expected_search1 = "host2";
 	const char *expected_search2 = "host3";
@@ -566,7 +591,7 @@ static void
 test_invalid_escaped_domain_searches (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	static const Option data[] = {
 		{ "domain_search", "host1\\aahost2\\032host3" },
 		{ NULL, NULL }
@@ -591,7 +616,7 @@ static void
 test_ip4_missing_prefix (const char *ip, guint32 expected_prefix)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const NMPlatformIP4Address *address;
 
 	options = fill_table (generic_options, NULL);
@@ -631,7 +656,7 @@ static void
 test_ip4_prefix_classless (void)
 {
 	GHashTable *options;
-	NMIP4Config *ip4_config;
+	gs_unref_object NMIP4Config *ip4_config = NULL;
 	const NMPlatformIP4Address *address;
 
 	/* Ensure that the missing-subnet-mask handler doesn't mangle classless
@@ -716,6 +741,7 @@ int main (int argc, char **argv)
 	g_test_add_func ("/dhcp/ip4-missing-prefix-8", test_ip4_missing_prefix_8);
 	g_test_add_func ("/dhcp/ip4-prefix-classless", test_ip4_prefix_classless);
 	g_test_add_func ("/dhcp/client-id-from-string", test_client_id_from_string);
+	g_test_add_func ("/dhcp/vendor-option-metered", test_vendor_option_metered);
 
 	return g_test_run ();
 }